Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
28.85% covered (danger)
28.85%
2687 / 9314
10.53% covered (danger)
10.53%
10 / 95
CRAP
0.00% covered (danger)
0.00%
0 / 1
WaitingController
28.80% covered (danger)
28.80%
2680 / 9307
10.53% covered (danger)
10.53%
10 / 95
2794834.58
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
100.00% covered (success)
100.00%
48 / 48
100.00% covered (success)
100.00%
1 / 1
1
 checkHash
0.00% covered (danger)
0.00%
0 / 92
0.00% covered (danger)
0.00%
0 / 1
6
 index
65.88% covered (success)
65.88%
195 / 296
0.00% covered (danger)
0.00%
0 / 1
239.05
 checkProperProfile
40.00% covered (warning)
40.00%
2 / 5
0.00% covered (danger)
0.00%
0 / 1
4.94
 detail
69.63% covered (success)
69.63%
658 / 945
0.00% covered (danger)
0.00%
0 / 1
2344.47
 getStrengthRating
95.00% covered (success)
95.00%
19 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 getLessonHistory
90.32% covered (success)
90.32%
56 / 62
0.00% covered (danger)
0.00%
0 / 1
23.48
 getPrimaryDetails
96.30% covered (success)
96.30%
26 / 27
0.00% covered (danger)
0.00%
0 / 1
6
 getFavCount
95.45% covered (success)
95.45%
21 / 22
0.00% covered (danger)
0.00%
0 / 1
5
 getAlbum
97.83% covered (success)
97.83%
45 / 46
0.00% covered (danger)
0.00%
0 / 1
5
 arrangeTeacherRecommendList
0.00% covered (danger)
0.00%
0 / 71
0.00% covered (danger)
0.00%
0 / 1
812
 checkReservation
88.46% covered (success)
88.46%
23 / 26
0.00% covered (danger)
0.00%
0 / 1
10.15
 start
76.92% covered (success)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
12.49
 teacherReserveList
89.21% covered (success)
89.21%
339 / 380
0.00% covered (danger)
0.00%
0 / 1
127.76
 updateChapterOptions
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
3
 result
97.64% covered (success)
97.64%
124 / 127
0.00% covered (danger)
0.00%
0 / 1
7
 loadMoreComments
100.00% covered (success)
100.00%
90 / 90
100.00% covered (success)
100.00%
1 / 1
25
 output
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 isCanCancel
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
5
 convertString
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 getTextbookOption
100.00% covered (success)
100.00%
85 / 85
100.00% covered (success)
100.00%
1 / 1
12
 getAllTextbookOption
99.40% covered (success)
99.40%
332 / 334
0.00% covered (danger)
0.00%
0 / 1
122
 saveTextbookPreset
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
1 / 1
16
 callLessonAlertandStartButton
80.21% covered (success)
80.21%
462 / 576
0.00% covered (danger)
0.00%
0 / 1
1003.39
 loadMoreSelfReviews
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 getUserReviews
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 getReserveAndCancelled
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
1 / 1
3
 triggerOrangeButton
80.00% covered (success)
80.00%
4 / 5
0.00% covered (danger)
0.00%
0 / 1
5.20
 deleteLessonOnair
0.00% covered (danger)
0.00%
0 / 27
0.00% covered (danger)
0.00%
0 / 1
110
 getTeacherOnlineList
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
12
 getSearchCondition
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 1
6
 getApologyList
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
2
 limitwarning
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
30
 updatedScheduleColor
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
20
 getAvatarDisabledDates
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 sp_counselor
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 counselor
0.00% covered (danger)
0.00%
0 / 178
0.00% covered (danger)
0.00%
0 / 1
1260
 customersupport
0.00% covered (danger)
0.00%
0 / 152
0.00% covered (danger)
0.00%
0 / 1
756
 counselingGetDisabledDates
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 counselorSlots
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 1
2070
 avatarSlots
0.00% covered (danger)
0.00%
0 / 219
0.00% covered (danger)
0.00%
0 / 1
4290
 counselingLimit
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
506
 avatarLimit
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
380
 checkCounselingReservationNow
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 1
110
 spDetail
0.00% covered (danger)
0.00%
0 / 262
0.00% covered (danger)
0.00%
0 / 1
1892
 spAvatarDetail
0.00% covered (danger)
0.00%
0 / 157
0.00% covered (danger)
0.00%
0 / 1
702
 avatar_detail
0.00% covered (danger)
0.00%
0 / 629
0.00% covered (danger)
0.00%
0 / 1
21170
 getTeacherReviews
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 1
870
 favoriteTextbookCategoryForReview
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 teacherAvatarStatus
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 checkMaintenanceForAlert
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
20
 isAvatar
65.22% covered (success)
65.22%
15 / 23
0.00% covered (danger)
0.00%
0 / 1
24.47
 counselorLatestLessonHistory
0.00% covered (danger)
0.00%
0 / 139
0.00% covered (danger)
0.00%
0 / 1
20
 avatarLatestLessonHistory
0.00% covered (danger)
0.00%
0 / 133
0.00% covered (danger)
0.00%
0 / 1
42
 userAvailPopularTeacher
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
30
 userValidForSSBEDT
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
5
 loadLiveLessonTeacher
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
756
 sms_questionnaire
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 avatar_sms_questionnaire
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
 checkCounselorTeacherButtonStatus
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
210
 emergencyLesson
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 teacherBadgeList
0.00% covered (danger)
0.00%
0 / 83
0.00% covered (danger)
0.00%
0 / 1
272
 avatarBadgeList
0.00% covered (danger)
0.00%
0 / 79
0.00% covered (danger)
0.00%
0 / 1
272
 teacherOccupation
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 teacherFeatures
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
 getSelfReviews
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
20
 getGenerationRating
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 getGenerationRatingAPI
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
56
 getUserMemo
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
30
 getReservationCancellationBreakdown
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 getActiveCampaign
0.00% covered (danger)
0.00%
0 / 535
0.00% covered (danger)
0.00%
0 / 1
21756
 getActiveCampaignStampData
0.00% covered (danger)
0.00%
0 / 177
0.00% covered (danger)
0.00%
0 / 1
272
 showCampaignModal
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
30
 generateTextbookTeacherRecommendAjax
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
342
 setUpAppreciationSelectionModalElementAjax
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 sendTeacherAppreciationAjax
0.00% covered (danger)
0.00%
0 / 69
0.00% covered (danger)
0.00%
0 / 1
420
 ajaxUpdateSystemTrouble
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
90
 reportProblem
0.00% covered (danger)
0.00%
0 / 65
0.00% covered (danger)
0.00%
0 / 1
156
 getApppreciationModal
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
72
 getAppreciationStatus
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getEvaluationDetail
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
42
 resetLessonReviewModal
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 finishOnlineLesson
0.00% covered (danger)
0.00%
0 / 272
0.00% covered (danger)
0.00%
0 / 1
7310
 getCounselorLessonHistory
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
342
 speakingTestAttendance
0.00% covered (danger)
0.00%
0 / 38
0.00% covered (danger)
0.00%
0 / 1
42
 getRegion
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 1
56
 getResidenceData
29.17% covered (danger)
29.17%
7 / 24
0.00% covered (danger)
0.00%
0 / 1
45.54
 countTeacherReservedLessons
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 getLiveCouponResult
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
2
 checkLessonStartButtonNormal
0.00% covered (danger)
0.00%
0 / 671
0.00% covered (danger)
0.00%
0 / 1
112560
 checkLessonStartButtonAvatar
0.00% covered (danger)
0.00%
0 / 653
0.00% covered (danger)
0.00%
0 / 1
94556
 checkLessonStartButtonCounselor
0.00% covered (danger)
0.00%
0 / 30
0.00% covered (danger)
0.00%
0 / 1
30
 checkLessonStartButtonCS
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
72
 updateLessonSystemTrouble
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 setAppreciationModalFinish
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3App::uses('AppController', 'Controller');
4App::uses('MyPageController', 'Controller');
5App::uses('SpTeacherController', 'Controller');
6App::uses('myArray', 'Lib');
7App::import('Controller', 'Textbook');
8App::uses('AwsFileServer', 'Lib');
9App::uses('Sanitize', 'Utility');
10
11class WaitingController extends AppController{
12    public $uses = array(
13        'Teacher',
14        'LessonOnair',
15        'LessonSchedule',
16        'LessonScheduleCancel',
17        'LessonLog',
18        'User',
19        'UsersDetail',
20        'UsersCourses',
21        'UsersTicket',
22        'UsersPoint',
23        'ShiftWorkOff',
24        'ShiftWorkOn',
25        'UsersClassEvaluation',
26        'UsersLessonsCountMinus',
27        'DefineMaster',
28        'UsersFavorite',
29        'UserTable',
30        'TeacherFeature',
31        'UsersLastViewedTextbook',
32        'TeacherImage',
33        'TeacherStatus',
34        'TextbookCategory',
35        'Payment',
36        'TextbookCourseConnect',
37        'CountryCode',
38        'PhoneVerifyCheckLog',
39        'CommonTeacherStatus',
40        'LessonOnairsLog',
41        'Textbook',
42        'TeacherBadge',
43        'TeacherCourseBadge',
44        'ShiftWorkHideDate',
45        'UsersFavorite',
46        'CounselingTable',
47        'Counseling',
48        'TeacherDetail',
49        'Timezone',
50        'TeacherWeeklyRating',
51        'PopularTeacherCampaignPeriod',
52        'BlockList',
53        'Avatar',
54        'HomeBasedRankBasicAmountLog',
55        'HomeBasedRankBasicAmount',
56        'UsersMemo',
57        'GlobalTextbookCategory',
58        'TeacherRankCoin',
59        'UserTextbookFavorite',
60        'UserSearchCondition',
61        'UsersTextbookInfo',
62        'Corporate',
63        'TeacherStudentConnection',
64        'TextbookConnect',
65        'TeacherStudentConnection',
66        'TeacherFeatureRating',
67        'ChatHistory',
68        'TeacherTextbookStat',
69        'LessonOnairsViewer',
70        'FeatureRatingItem',
71        'UsersFavoriteCategoriesTeacher',
72        'LessonOnairsLogTimeExtension',
73        'LessonOnairsViewersLog',
74        'UsersTextbookInfo',
75        'UsersFavoriteCategories',
76        'UserFeatureRatingLastVoted',
77        'TeacherDetails',
78        'UserFirstLesson',
79        'AppreciationMessage',
80        'UsersClassEvaluationFeatureRating',
81        'ViewersClassEvaluation',
82        'TeacherCoinBox',
83        'LessonOnairsLogTable',
84        'LessonBookmark',
85        'CampaignPcBanner',
86        'ReservationCoin',
87        'CountryRegion',
88        'CampaignInstructor',
89        'CampaignTagControl',
90        'ProhibitedWord',
91        'TitleThresholdTeacher',
92        'ViewerFeatureRatingLastVoted',
93        'PlanTeacherCategoryBlock'
94    );
95
96    public $helpers = array('Html', 'Form');
97    public $selfReviewLimit = 10;
98    public $components = array('Cookie'); //NC-3096 add cookie
99    public $defaultMemoryLimit = null;
100    public $blockMemberSettings = [];
101    public function beforeFilter() {
102        parent::beforeFilter();
103        //NC-3096 cookies
104        $this->Cookie->name = 'searchTeacherForm';
105        $this->Cookie->time = 86400 ;  // 1 day
106        $this->Cookie->domain = $_SERVER['SERVER_NAME'];
107
108        $allowActionArr = array(
109            'index',
110            'detail',
111            'avatar_detail',
112            'avatarSlots',
113            'teacherReserveList',
114            'loadMoreComments',
115            'isShiftWorkCancelled',
116            'callLessonAlertandStartButton',
117            'counselor',
118            'sp_counselor',
119            'counselorSlots',
120            'checkCounselingReservationNow',
121            'teacherAvatarStatus',
122            'getTeacherReviews',
123            'loadLiveLessonTeacher',
124            'limitwarning',
125            'isCanCancel',
126            'teacherBadgeList',
127            'teacherOccupation',
128            'teacherFeatures',
129            'getSelfReviews',
130            'getGenerationRating',
131            'getReservationCancellationBreakdown',
132            'getAlbum',
133            'getFavCount',
134            'getLessonHistory',
135            'getStrengthRating',
136            'getGenerationRatingAPI',
137            'avatarBadgeList',
138            'getPrimaryDetails',
139            'finishOnlineLesson',
140            'speakingTestAttendance',
141            'getRegion',
142            'countTeacherReservedLessons',
143            'checkLessonStartButtonNormal',
144            'checkLessonStartButtonAvatar'
145        );
146
147        $phoneNumbers = $this->CountryCode->getCountryCodesWithSmsAuth();
148        $this->set('phoneNumbers', $phoneNumbers);
149
150        $this->Auth->allow($allowActionArr);
151        //Timezone timedifference
152        $this->set('timeDiffSecond', $this->timeDiffSecond);
153        $this->defaultMemoryLimit = ini_get("memory_limit");
154        $this->blockMemberSettings = $this->PlanTeacherCategoryBlock->getPlanTeacherCategoryBlock($this->sharedUserData['User']);
155    }
156
157    private function checkHash($table , $chatHash) { //returns data if chat_hash exist
158        $fields = array(
159            $table.'.id',
160            $table.'.teacher_id',
161            $table.'.user_id',
162            $table.'.start_time',
163            $table.'.end_time',
164            $table.'.lesson_type', // NC-3824
165            $table.'.lesson_finish', // NC-3824,
166            $table.'.created', // NC-3824
167            $table.'.user_agent',
168            $table.'.lesson_system_trouble',
169            $table.'.connect_id', // NC-5884
170            $table.'.live_lesson_flg',
171            $table.'.connect_id',
172            $table.'.lesson_schedule_id',
173            $table.'.counselor_flag',
174            $table.'.textbook_category_id',
175            'teacher.id',
176            'teacher.name',
177            'teacher.jp_name',
178            'teacher.image_url',
179            'teacher.home_flg', // NC-3824
180            'teacher.rank_coin_id', // NC-3824
181            'teacher.first_lesson_date', // NC-3824
182            'teacher.promote_date', // NC-3824
183            'TeacherDetail.referrer_id', // NC-3824
184            'teacher.counseling_flg', //NC-4589
185            'teacher.avatar_id',
186            'teacher.avatar_flg',
187            'teacher.avatar_parent_flg',
188            'User.nickname',
189            'User.created',
190            'User.fail_flg',
191            'User.charge_flg',
192            'User.birthday',
193            'User.birthday_show_flg',
194            'Connect.id',
195            'Connect.category_id',
196            'Connect.textbook_id',
197            'User.network_review_flg',
198            'User.textbook_review_flg',
199            'User.teacher_review_flg',
200            'User.next_textbook_flg',
201            'User.lesson_review_flg'
202        );
203
204        if ($table == 'LessonOnairsLog') {
205            array_push($fields, 'LessonOnairsLog.onair_id');
206        }
207
208        $data = array(  
209        'conditions' => 
210              array(
211                $table.'.chat_hash' => $chatHash
212               ),  
213        'joins' =>
214                  array(
215                    array(
216                        'table' => 'teachers',
217                        'alias' => 'teacher',
218                        'type' => 'left',
219                        'foreignKey' => false,
220                        'conditions' => array(
221                            'teacher.id ='.$table.'.teacher_id'
222                        )
223                    ),        
224                    array(
225                        'table' => 'users',
226                        'alias' => 'User',
227                        'type' => 'left',
228                        'conditions' => array(
229                            'User.id = '.$table.'.user_id'
230                        )
231                    ),
232                    array(
233                        'table' => 'textbook_connects',
234                        'alias' => 'Connect',
235                        'type' => 'left',
236                        'conditions' => array(
237                            'Connect.id = '.$table.'.connect_id'
238                        )
239                    ),
240                    array( // NC-3824
241                        'table' => 'teacher_details',
242                        'alias' => 'TeacherDetail',
243                        'type' => 'left',
244                        'conditions' => array(
245                            'TeacherDetail.teacher_id = '.$table.'.teacher_id'
246                        )
247                    )
248                ),
249
250        'fields' => $fields,                
251        'order' => array($table.'.id' => 'DESC')            
252        );
253
254        return $data;
255    }
256
257    /**
258 * @api {get} /user/:language/waiting index()
259 * @apiName index
260 * @apiGroup Waiting
261 * @apiDescription Retrieves the index page for the waiting area in Native Camp. It returns various information about the user, teachers, and campaigns.
262 *
263 * @apiParam {String} language The language code for the page.
264 * 
265 * @apiSuccess {Object[]} allBanners The list of campaign banners.
266 * @apiSuccess {String} allBanners.id The ID of the banner.
267 * @apiSuccess {String} allBanners.campaign_url The URL of the campaign.
268 * @apiSuccess {String} allBanners.start The start date of the campaign.
269 * @apiSuccess {String} allBanners.end The end date of the campaign.
270 * @apiSuccess {String} allBanners.image_url The image URL of the campaign.
271 * @apiSuccess {String} allBanners.event_tracking_tag The event tracking tag of the campaign.
272 * @apiSuccess {String} allBanners.display_position The display position of the campaign.
273 * @apiSuccess {Object} searchCount The count of saved search conditions.
274 * @apiSuccess {Object} userpoint The user points.
275 * @apiSuccess {String} localizeDir The localization directory.
276 * @apiSuccess {Object} selectOptions The select options for the teacher search.
277 * @apiSuccess {Object} selectOptions.availability The availability options.
278 * @apiSuccess {Object} selectOptions.classification The classification options.
279 * @apiSuccess {String} headtext The head text for the page.
280 * @apiSuccess {Object[]} badges The list of badges.
281 * @apiSuccess {Boolean} isLoggedIn Indicates if the user is logged in.
282 * @apiSuccess {Object} userData The user data.
283 * @apiSuccess {Object} userData.User The user object.
284 * @apiSuccess {String} userData.User.id The ID of the user.
285 * @apiSuccess {String} userData.User.currency_code The currency code of the user.
286 * @apiSuccess {String} userData.User.card_company The card company of the user.
287 * @apiSuccess {Object} userDataObj The user data object.
288 * @apiSuccess {Number} paymentPlanId The payment plan ID of the user.
289 * @apiSuccess {Number} userLang The language ID of the user.
290 * @apiSuccess {Object[]} seriesSpecialArr The list of special series.
291 * @apiSuccess {Object} seriesSelected The selected series.
292 * @apiSuccess {Object} counselor The counselor object.
293 * @apiSuccess {String} counselor.name The name of the counselor.
294 * @apiSuccess {String} counselor.jp_name The Japanese name of the counselor.
295 * @apiSuccess {String} counselor.image_url The image URL of the counselor.
296 * @apiSuccess {String} counselor.country_name The country name of the counselor.
297 * @apiSuccess {Boolean} isHide Indicates if the counselor is hidden.
298 * @apiSuccess {Object[]} favId The list of favorite teacher IDs.
299 * @apiSuccess {Object[]} teacherFavs The list of favorite teachers with colors.
300 * @apiSuccess {Object[]} teacherFavsColors The list of favorite teacher colors.
301 * @apiSuccess {Object[]} avatarActiveId The list of active avatar IDs.
302 * @apiSuccess {Boolean} teddyFav Indicates if the teddy avatar is favorited.
303 * @apiSuccess {Object[]} occupationData The list of teacher occupations.
304 * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
305 * @apiSuccess {Boolean} hideCouselorFromMember Indicates if the counselor information should be hidden from the member.
306 * @apiSuccess {Boolean} is_lite_plan_user Indicates if the user is on a lite plan.
307 * @apiSuccess {Object[]} teacherList The list of teachers.
308 * @apiSuccess {Object[]} regions The list of regions.
309 * @apiSuccess {Object[]} coinData The list of coin data.
310 * @apiSuccess {Object} searchData The search data.
311 * @apiSuccess {Boolean} isLogin Indicates if the user is logged in.
312 * @apiSuccess {Number} savedConditionsCount The count of saved search conditions.
313 * @apiSuccess {Object} preset The preset textbook information.
314 * @apiSuccess {Object} searchCondition The search condition.
315 * @apiSuccess {Object[]} featureFilter The list of feature filters.
316 * @apiSuccess {Object} user The user object.
317 * @apiSuccess {String} user.id The ID of the user.
318 * @apiSuccess {String} user.name The name of the user.
319 * @apiSuccess {String} disconnectionChatHash The disconnection chat hash.
320 * @apiSuccess {Object[]} coins The list of coins.
321 * @apiSuccess {Object} campaignTagSearch The campaign tag search status.
322 *
323 * @apiSuccessExample {json} Success-Response:
324 *     {
325 *         "allBanners": [
326 *             {
327 *                 "id": "1",
328 *                 "campaign_url": "http://example.com/campaign",
329 *                 "start": "2023-12-01",
330 *                 "end": "2023-12-31",
331 *                 "image_url": "http://example.com/image.jpg",
332 *                 "event_tracking_tag": "tag1",
333 *                 "display_position": "top"
334 *             }
335 *         ],
336 *         "searchCount": 5,
337 *         "userpoint": 100,
338 *         "localizeDir": "en",
339 *         "selectOptions": {
340 *             "availability": {...},
341 *             "classification": {...}
342 *         },
343 *         "headtext": "Welcome to the waiting area",
344 *         "badges": [...],
345 *         "isLoggedIn": true,
346 *         "userData": {
347 *             "User": {
348 *                 "id": "123",
349 *                 "currency_code": "USD",
350 *                 "card_company": "Visa"
351 *             }
352 *         },
353 *         "userDataObj": {...},
354 *         "paymentPlanId": 1,
355 *         "userLang": 1,
356 *         "seriesSpecialArr": [...],
357 *         "seriesSelected": {...},
358 *         "counselor": {
359 *             "name": "John Doe",
360 *             "jp_name": "ジョン・ドウ",
361 *             "image_url": "http://example.com/image.jpg",
362 *             "country_name": "Japan"
363 *         },
364 *         "isHide": false,
365 *         "favId": [...],
366 *         "teacherFavs": [...],
367 *         "teacherFavsColors": [...],
368 *         "avatarActiveId": [...],
369 *         "teddyFav": true,
370 *         "occupationData": [...],
371 *         "counselorLampStatus": {...},
372 *         "hideCouselorFromMember": false,
373 *         "is_lite_plan_user": true,
374 *         "teacherList": [...],
375 *         "regions": [...],
376 *         "coinData": [...],
377 *         "searchData": {...},
378 *         "isLogin": true,
379 *         "savedConditionsCount": 5,
380 *         "preset": {...},
381 *         "searchCondition": {...},
382 *         "featureFilter": [...],
383 *         "user": {
384 *             "id": "123",
385 *             "name": "John Doe"
386 *         },
387 *         "disconnectionChatHash": "abc123",
388 *         "coins": [...],
389 *         "campaignTagSearch": {...}
390 *     }
391 *
392 * @apiError {String} status The status of the request (NG).
393 * @apiError {String} message The error message.
394 *
395 * @apiErrorExample {json} Error-Response:
396 *     {
397 *         "status": "NG",
398 *         "message": "Invalid request."
399 *     }
400 * 
401 * @apiSampleRequest off
402 */
403    public function index() {
404        // NJ-37582 redirect to appointment
405        $this->redirect('/appointment');
406        
407        $this->Teacher->hasAfterFind = true;
408        //mobile view only
409        
410        if ($this->RequestHandler->isMobile()) {
411            $this->layout = 'mobile';
412            $userpoints = $this->UsersPoint->getCurrentUserPoint($this->Auth->user('id'));
413
414            myTools::initializeApiTunnel(['SearchConditionsController']);
415
416            $displayRestrictionParams = array(
417                'lang' => $this->localizeDir
418            );
419
420            $searchConditions = new SearchConditionsController();
421            $params= array(
422                "users_api_token" => $this->Auth->user('api_token'),
423                "nc_terminal_type" => Configure::read('nc_terminal_type.pc'),
424                "displayRestrictionParams" => $displayRestrictionParams
425            );
426            $searchConditions->params = $params;
427
428            $search = json_decode($searchConditions->index(), true);
429            $savedSearchCount = count($search['conditions'] ?? []);
430
431            $this->set('searchCount', $savedSearchCount);
432            $this->set('userpoint', $userpoints);
433            $this->set('localizeDir',  $this->localizeDir);
434            return $this->render('/Mobile/Teacher/index');
435        }
436
437        $params = $this->params->query;
438        if (isset($params['stealth'])) {
439            TeacherTable::setStealthSettings($this->Cookie, $params['stealth']);
440        }
441        $selectOptions = array(
442            'availability' => TeacherTable::teacherAvailSelect2(),
443            //'nationality' => TeacherTable::teacherLocationSelect()
444            'classification' => TeacherTable::teacherClassificationSelect()
445        );
446        $this->set('selectOptions', $selectOptions);
447        $this->set('headtext', Configure::read('my.meta.waiting-index.headtext'));
448        $this->set('badges', TeacherBadgeTable::displayBadges());
449        $this->set('isLoggedIn', $this->Auth->loggedIn());
450        
451        $userData = $this->sharedUserData;//use shared user data 
452        // NJ-46: mypage banners
453        $userDataObj = new UserTable($userData['User']);
454        $paymentPlanId = $userDataObj->getMembershipTypeIndex();
455        $userLang = $this->CountryCode->getUserLanguageId($this->localizeDir);
456
457        // - conditions
458        $conditions = array(
459            'CampaignPcBanner.status' => 1,
460            'CampaignPcBannerCurrency.currency_code' => $userData['User']['currency_code'],
461            'CampaignPcBannerLanguage.language_id' => $userLang,
462        );
463
464        if ($userData['User']['card_company']) {
465            $conditions['CampaignPcBanner.payment_company LIKE'] = '%' . $userData['User']['card_company'] . '%';
466        }
467
468        if ($paymentPlanId) {
469            $conditions['FIND_IN_SET(?, CampaignPcBanner.user_status)'] = $paymentPlanId;
470        }
471        $this->log("[CampaignSettingsModal] conditions -> " .  json_encode($conditions), "debug");
472
473        $this->CampaignPcBanner->openDBReplica();
474        $allBanners = $this->CampaignPcBanner->find('all', array(
475            'fields' => array(
476                'CampaignPcBanner.id',
477                'CampaignPcBanner.campaign_url',
478                'CampaignPcBanner.start',
479                'CampaignPcBanner.end',
480                'CampaignPcBanner.image_url',
481                'CampaignPcBanner.event_tracking_tag',
482                'CampaignPcBanner.display_position'
483            ),
484            'conditions' => $conditions,
485            'joins' => array(
486                array(
487                    'table' => 'campaign_pc_banner_currencies',
488                    'alias' => 'CampaignPcBannerCurrency',
489                    'type' => 'LEFT',
490                    'conditions' => array('CampaignPcBannerCurrency.campaign_pc_banner_id = CampaignPcBanner.id')
491                ),
492                array(
493                    'table' => 'campaign_pc_banner_languages',
494                    'alias' => 'CampaignPcBannerLanguage',
495                    'type' => 'LEFT',
496                    'conditions' => array('CampaignPcBannerLanguage.campaign_pc_banner_id = CampaignPcBanner.id')
497                )
498            ),
499            'order' => 'CampaignPcBanner.priority_number ASC',
500            'recursive' => -1,
501        ));
502        $this->CampaignPcBanner->closeDBReplica();
503        $this->set('allBanners', $allBanners);
504
505        //instantiate view
506        $view = new View($this, false);
507        $view->layout = false;
508        //fetch data
509        $this->Teacher->hasAfterFind = true;
510        //NC-4548 from kids text description course
511        if (isset($_COOKIE['fromKidsDescription']) && $_COOKIE['fromKidsDescription'] !== 'null') {
512            $kidsCourseTeacher = array(
513                'sortRadio' => 'status',
514                'statusRadio' => 'all',
515                'teacherFeature' => array(0 => 'kids'),
516                'textbookRadioVal' => '2',
517                'courseOptionSearchCourseId' => '2',
518                'courseOptionChapterId' => '1',
519                'courseOptionLessonTextId' => '209',
520                'courseOptionConnectId' => '1',
521                'seriesOptionSearchTextBookCategoryId' => '11',
522                'badgeIds' => '11'
523            );
524
525            $this->Cookie->write('searchData', $kidsCourseTeacher);
526        }
527
528        //NJ-9440 - add status ALL + Live flg
529        if (isset($this->request->query['from_live_lesson_usage']) && $this->request->query['from_live_lesson_usage'] == 1) {
530            $liveTeachers = array(
531                'sortRadio' => 'status',
532                'statusRadio' => 'all',
533                'searchLiveLesson' => '1'
534            );
535            $this->Cookie->write('searchData', $liveTeachers);
536        }
537
538        if (!class_exists('myMemcached')) {
539            App::uses('myMemcached', 'Lib');
540        }
541        $memcache = new myMemcached();
542        if ($this->Auth->loggedIn()) {
543            $memKey = "searchCallanUsers_{$this->sharedUserData['User']['id']}";
544        } else {
545            $memKey = "searchCallanUsers";
546        }
547        if ($memSearchReserveData = $memcache->get($memKey)) {
548            $this->Cookie->write('searchData', $memSearchReserveData);
549            $memcache->delete($memKey);
550        }
551
552        // NJ-5836
553        $displayRestrictionParams = array(
554            'lang' => $this->localizeDir
555        );
556
557        // get display restriction setting
558        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
559
560        $query = array();
561        if ($this->isStudySapuriUser) {
562            // Get all Book
563            $getAllBookArr = array(
564                'user_id' => $this->Auth->user('id'),
565                'textbook_type' => 2,
566                'arrange_data' => 'trunk',
567                'preset' => 'off',
568                'user_locale' => $this->localizeDir,
569                'load_description' => false
570            );
571            $seriesCategoryData = $this->Textbook->getTextbooks($getAllBookArr);
572            $seriesArr = $seriesCategoryData['res_data'];
573
574            $getSeriesPresetArr = array(
575                'user_id' => $this->Auth->user('id'),
576                'textbook_type' => 2,
577                'select_method' => 'first',
578                'preset' => 'off',
579                'displayRestriction' => $displayRestriction
580            );
581            $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
582            $seriesPreset = $seriesPresetData['res_data'];
583            $seriesId = $seriesPreset['TextbookCategory']['id'];
584            // NC-7228 set series id from saved search condition
585            $searchData = $this->Cookie->read('searchData');
586            if(isset($searchData['seriesOptionSearchTextBookCategoryId']) && !empty($searchData['seriesOptionSearchTextBookCategoryId'])){
587                $seriesId = $searchData['seriesOptionSearchTextBookCategoryId'];
588            }
589            $seriesSelected = isset($seriesArr[$seriesId]) ? $seriesArr[$seriesId] : 0;
590
591            if ($seriesSelected) {
592                $query['badgeIds'] = $seriesSelected;
593            }
594
595            $this->set('seriesSpecialArr', $seriesArr);
596            $this->set('seriesSelected', $seriesSelected);
597        }
598        // - NJ-6390
599        $searchParams = !empty($query) && $query? $query : $this->Cookie->read('searchData');
600        $highLightFlag = null;
601        if (isset($searchParams['keywordText']) && $searchParams['keywordText']) {
602            // - 1 = able to highlight the keyWord freeword search
603            $highLightFlag = 1;
604
605            // -delete session
606            $this->Session->delete('freeword-'.$this->Auth->user('id'));
607
608            // - add session for freewordArray
609            $this->Session->write('freeword-'.$this->Auth->user('id'), $this->request->data['keywordText']);
610        }
611
612        $data = [];
613
614        if (!$this->isStudySapuriUser) {
615            $counselor = $this->Teacher->find('first', array(
616                'fields' => array(
617                    'Teacher.name',
618                    'Teacher.jp_name',
619                    'Teacher.image_url',
620                    'CountryCode.country_name'
621                ),
622                'joins' => array(
623                    array(
624                        'type' => 'LEFT',
625                        'table' => 'country_codes',
626                        'alias' => 'CountryCode',
627                        'conditions' => 'Teacher.homeland2 = CountryCode.id'
628                    )
629                ),
630                'conditions' => array('Teacher.id' => Configure::read('default_counselor_detail')),
631                'recursive' => -1
632            ));
633        }
634
635        # check counselor if hidden
636        $where = array(
637            'user_id' => $this->Auth->user('id'),
638            'teacher_id' => Configure::read('default_counselor_detail')
639        );
640        $isHide = $this->BlockList->isTeacherHide($where);
641        $this->set('isHide', $isHide);
642
643        $favId = $this->Auth->loggedIn() ? $this->UsersFavorite->getTeacherIdList($this->Auth->user('id')) : array();
644//        NJ-10550
645        $teacherFavs = $this->Auth->loggedIn() ?
646            $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => array_values($favId)]) : [];
647        $colors = $this->UsersFavoriteCategoriesTeacher::COLORS;
648        $teacherFavsColors = []; //default
649
650        //-validate array variable
651        if (
652            $teacherFavs && 
653            is_array($teacherFavs)
654        ) {
655            $teacherFavsColors = array_map(function ($val) use ($colors) {
656                $index = array_search($val, array_column($colors, 'code'));
657                return $index >= 0 ? $colors[$index]['hex'] : '#F0295D';
658            }, $teacherFavs);
659        }
660
661        $this->set('teacherFavsColors', $teacherFavsColors);
662        // NC-7031 - avatar teachers
663        $avatarIdArr = array();
664        $teddyFav = false;
665        $getAvatarId = $this->Teacher->getParentAvatarTeacher();
666        if ($getAvatarId) {
667            $avatarIdArr = array_values($getAvatarId);
668
669            if ( $this->Auth->loggedIn() ) { // logged in
670                if ( $favId ) {
671                    // teddy
672                    $favAvaTParams = array(
673                        "avatar_id" => Configure::read('avatar_id.teddy'),
674                        "teacher_id" => $favId,
675                    );
676                    $checkTeddyFav = $this->Teacher->checkFavAvatarTeacher($favAvaTParams);
677
678                    if ($checkTeddyFav) {
679                        $teddyFav = true;
680                    }
681                }
682            }
683        }
684        //NC-9215 get teacher occupation industry and position
685        $this->set('occupationData', ClassRegistry::init('TeacherOccupationDetail')->getActiveOccupation());
686
687        // NJ-20272 : get counselor teacher lamp status
688        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
689
690        // NJ-9489 : check if membership is allowed to display counselor information
691         $_userData = $this->sharedUserData;
692        $hideCouselorFromMember = 0;
693        $n_isLitePlanUser = false;
694        if ($_userData) {
695            $_userPaymentPlan = $_userData['User']['payment_plan_id'];
696  
697            if (
698                  !$_userPaymentPlan ||
699                  in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
700            ) {
701                $hideCouselorFromMember = 1;
702            }
703
704            // NJ-37250 : set lite plan user flag 
705            if ($_userPaymentPlan && in_array($_userPaymentPlan, Configure::read('lite_payment_plans'))) {
706                $n_isLitePlanUser = true;
707            }
708        
709        }
710        $this->set('is_lite_plan_user',$n_isLitePlanUser);
711        $this->set('hideCouselorFromMember',$hideCouselorFromMember);
712
713        $view->set(array(
714            'teddyFav' => $teddyFav,
715            'avatarActiveId' => $avatarIdArr,
716            'counselor' => isset($counselor) ? $counselor : null,
717            'teachers' => isset($data['teacherData']) ? $data['teacherData'] : array(),
718            'counterData' => isset($data['limitGauge']) ? $data['limitGauge'] : 0,
719            'teacherRecordCount' => isset($data['teacherRecordCount']) ? $data['teacherRecordCount'] : 0,
720            'recordCount' => isset($data['teacherData']) ? count($data['teacherData']) : 0,
721            'limitRecord' => isset($data['limit']) ? $data['limit'] : 0,
722            'estimateRecord' => isset($data['limit']) && isset($data['teacherData']) ? count($data['teacherData']) * $data['limit'] : 0, 
723            'messageFlag' => false,
724            'isLoggedIn' => $this->Auth->loggedIn(),
725            'caller' => 'waiting',
726            'favId' => $favId,
727            'userId' => $this->Auth->loggedIn() ? $this->sharedUserData['User']['id'] : '',
728            'isHide' => $isHide,
729            'highLightFlag' => $highLightFlag,
730            'counselorLampStatus' => $counselorLampStatus
731        ));
732        $teacherList = $view->render('/MyPage/online_teachers');
733        $this->set('teacherList', $teacherList);
734
735
736        // NC-9142
737        $badges = $this->Textbook->getPresetTextbookSeriesId();
738
739        $userLangId = $this->CountryCode->getUserLanguageId(!empty($_userData['User']['native_language2']) ? $_userData['User']['native_language2'] : Configure::read('english_language'));
740
741        // - get regions list
742        $this->set('regions', $this->Teacher->getAvailableNationality($this->localizeDir, ($this->isStudySapuriUser ? true : false), ($this->isStudySapuriUser ? $badges : '')), array(), $userLangId); //nationalities of teachers
743        
744        $this->set('coinData', $this->TeacherRankCoin->getCoinAmount()); // set coin dropdown
745        $defaultSearchData = $this->Cookie->read('searchData');
746
747        if (isset($this->request->query['campaign_filter']) && $this->request->query['campaign_filter']) {
748            $campaignFilter = $this->request->query['campaign_filter'];
749            $defaultSearchData['statusRadio'] = 'all';
750            $defaultSearchData['textbookRadioVal'] = 2;
751            $this->Cookie->write('searchReserveData.seriesOptionSearchTextBookCategoryId', Configure::read('campaign_config.'.$campaignFilter.'.ENV.'.Configure::read('ENVIRONMENT').'.textbook_category_id'));
752        }
753        $this->set('searchData', $defaultSearchData);
754        $this->set('isLogin', $this->Auth->loggedIn());
755
756        // NC-7228 get stored search conditions
757        $savedConditionsCount = $this->UserSearchCondition->getSavedConditionsCount($this->sharedUserData['User']['id'], $n_isLitePlanUser);
758        $this->set('savedConditionsCount', $savedConditionsCount);
759
760        // set default preset params
761        $presetParams = array(
762            'user_id' => $this->Auth->user('id'),
763            'lang' => (isset($this->localizeDir) && $this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
764            'is_pc_flg' => 1
765        );
766
767        //
768        if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) && 
769            ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
770          ){
771            $presetParams['userValidForSSBEDT'] = true;
772        }
773
774        //
775        if (isset($this->sharedUserData['User'])) {
776            //
777            $userDataObj = new UserTable($this->sharedUserData['User']);
778
779            //
780            if (!empty($userDataObj->getMembershipTypeIndex())) {
781                $presetParams["userMembershipType"] = $userDataObj->getMembershipTypeIndex();
782            }
783
784            $presetParams['native_language2'] = $userDataObj->native_language2;
785
786        }
787
788        // get preset data
789        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
790
791        //
792        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
793            // for preset
794            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
795            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
796
797        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
798            // use last viewed textbook if no preset data.
799            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
800            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
801
802        }
803
804        // initial fetch preset 
805        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
806
807        // if no preset fetched - unsupported, fetch for tb with sort prioty 1
808        if(!$preset) {
809            unset($presetParams['connect_id']);
810            unset($presetParams['last_opened_date']);
811            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
812        }
813
814        $this->set('preset', $preset);
815        $this->set('searchCondition', $this->Session->read('savedSearchCondition'));
816        //- 
817        $this->set('featureFilter', $this->FeatureRatingItem->getFeatureFilters(['langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)]));
818
819        // - NJ-11223 
820        $oUserData = new UserTable($this->sharedUserData['User']);
821        $this->set('user', $oUserData);
822        $this->Session->delete('savedSearchCondition');
823
824        // NJ-21309
825        $memcached = new myMemcached();
826        $disconnectionChatHash = $memcached->get('disconnectionChatHash');
827        $this->set('disconnectionChatHash', $disconnectionChatHash);
828
829
830        //- NJ-36852
831        $this->ReservationCoin->openDBReplica();
832        $coins = $this->ReservationCoin->find('all', ['conditions'=> array('status' => 1)]);
833        $this->ReservationCoin->closeDBReplica();
834
835          $coinArray = [];
836        if($coins && is_array($coins)) {
837            foreach ($coins as $c) {
838                $coinArray[] = $c['ReservationCoin']['coin'];
839            }
840        } 
841        
842        $this->set("coins", json_encode($coinArray));
843
844        # NJ-19429: Search Campaign Teachers
845        $campaignTagSearch = $this->CampaignTagControl->getCampaignTagStatusPC($this->sharedUserData['User']['id']);
846        $this->set('campaignTagSearch', $campaignTagSearch);
847        
848    }
849
850    private function checkProperProfile($teacherId) {
851        if (!is_numeric($teacherId)) {
852            $this->redirect('/waiting/detail/'.intval($teacherId), '301');
853        } else if (!ctype_digit($teacherId)){
854            $this->log("Invalid [teacher_id] ".$teacherId, "error");
855            throw new NotFoundException();
856        }
857
858        /* commented conflict to localization
859        if (isset($this->params->url) && $this->params->url != 'waiting/detail/'.$teacherId) {
860            $this->redirect('/waiting/detail/'.$teacherId, '301');
861        }*/
862    }
863
864    /**
865     * @api {get} /user/:language/waiting/detail/:teacherId/:highLightFlag detail()
866     * @apiName detail
867     * @apiGroup Waiting
868     * @apiDescription Retrieves the detailed information for a specific teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
869     *
870     * @apiParam {String} language The language code.
871     * @apiParam {String} teacherId The ID of the teacher.
872     * @apiParam {String} [highLightFlag] The highlight flag.
873     * 
874     * @apiSuccess {Object} teacher The teacher object.
875     * @apiSuccess {String} teacher.id The ID of the teacher.
876     * @apiSuccess {String} teacher.name The name of the teacher.
877     * @apiSuccess {String} teacher.image The image URL of the teacher.
878     * @apiSuccess {Object} country The country object.
879     * @apiSuccess {String} country.name The name of the country.
880     * @apiSuccess {String} country.code The code of the country.
881     * @apiSuccess {Object} timezone The timezone object.
882     * @apiSuccess {String} timezone.name The name of the timezone.
883     * @apiSuccess {String} timezone.offset The offset of the timezone.
884     * @apiSuccess {Object} tutorCategory The tutor category object.
885     * @apiSuccess {String} tutorCategory.name The name of the tutor category.
886     * @apiSuccess {Number} timeDiff The time difference in seconds.
887     * @apiSuccess {Object} onair The on-air data.
888     * @apiSuccess {String} onair.id The ID of the on-air data.
889     * @apiSuccess {String} onair.status The status of the on-air data.
890     * @apiSuccess {String} userId The ID of the user.
891     * @apiSuccess {Object[]} series The list of textbook series.
892     * @apiSuccess {String} series.id The ID of the series.
893     * @apiSuccess {String} series.name The name of the series.
894     * @apiSuccess {Object[]} teacherTbRatings The teacher textbook ratings.
895     * @apiSuccess {String} teacherTbRatings.id The ID of the rating.
896     * @apiSuccess {String} teacherTbRatings.rating The rating value.
897     * @apiSuccess {Number} historyYear The number of years of teaching history.
898     * @apiSuccess {Number} historyMonth The number of months of teaching history.
899     * @apiSuccess {Object} teacherStatus1 The teacher status object.
900     * @apiSuccess {String} teacherStatus1.status The status of the teacher.
901     * @apiSuccess {Object} oOnair The on-air object.
902     * @apiSuccess {String} oOnair.id The ID of the on-air object.
903     * @apiSuccess {String} oOnair.status The status of the on-air object.
904     * @apiSuccess {Number} teacherTitleThreshold The teacher title threshold.
905     * @apiSuccess {Number} initialTeacherStatus The initial teacher status.
906     * @apiSuccess {Boolean} isFav Indicates if the teacher is favorited by the user.
907     * @apiSuccess {Boolean} isHide Indicates if the teacher is hidden by the user.
908     * @apiSuccess {Boolean} unsupportedBrowser Indicates if the browser is unsupported.
909     * @apiSuccess {Boolean} canReport Indicates if the user can report the teacher.
910     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
911     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates if it is the user's first time logging in.
912     * @apiSuccess {Boolean} paidParent Indicates if the user is a paid parent.
913     * @apiSuccess {Number} velifyCount The count of phone verification logs.
914     * @apiSuccess {Object[]} countryCodes The list of country codes.
915     * @apiSuccess {String} countryCodes.code The code of the country.
916     * @apiSuccess {String} countryCodes.name The name of the country.
917     * @apiSuccess {Object} userCountry The user's country information.
918     * @apiSuccess {String} userCountry.name The name of the user's country.
919     * @apiSuccess {String} userCountry.code The code of the user's country.
920     * @apiSuccess {Boolean} deviceNotSupported Indicates if the device is not supported.
921     * @apiSuccess {Object} userLang The user's language information.
922     * @apiSuccess {String} userLang.name The name of the user's language.
923     * @apiSuccess {String} userLang.code The code of the user's language.
924     * @apiSuccess {Object} getCRData The country residence data.
925     * @apiSuccess {String} getCRData.country The country of residence.
926     * @apiSuccess {Object} residenceData The residence data.
927     * @apiSuccess {String} residenceData.city The city of residence.
928     * @apiSuccess {Boolean} residenceFlg Indicates if the residence flag is set.
929     * @apiSuccess {Boolean} login Indicates if the user is logged in.
930     * @apiSuccess {Object} preset The preset textbook information.
931     * @apiSuccess {String} preset.id The ID of the preset textbook.
932     * @apiSuccess {String} preset.name The name of the preset textbook.
933     * @apiSuccess {Boolean} presetIsLiveTextbook Indicates if the preset textbook is for live lessons.
934     * @apiSuccess {Object[]} apologyList The list of apologies.
935     * @apiSuccess {String} apologyList.id The ID of the apology.
936     * @apiSuccess {String} apologyList.message The message of the apology.
937     * @apiSuccess {Boolean} isNormalLitePlanUser Indicates if the user is on a normal lite plan.
938     * @apiSuccess {Object} getKeepMemo The keep memo information.
939     * @apiSuccess {String} getKeepMemo.id The ID of the keep memo.
940     * @apiSuccess {String} getKeepMemo.memo The memo text.
941     * @apiSuccess {String} textbookConnectId The textbook connect ID.
942     * @apiSuccess {Number} textbookCategoryTypeId The textbook category type ID.
943     * @apiSuccess {Boolean} highLightFlag Indicates if the highlight flag is set.
944     * @apiSuccess {Number} liveCoin The live lesson coin amount.
945     * @apiSuccess {Number} order The order of the teacher reviews.
946     * @apiSuccess {Object[]} lesson_history_data The lesson history data.
947     * @apiSuccess {String} lesson_history_data.id The ID of the lesson history.
948     * @apiSuccess {String} lesson_history_data.date The date of the lesson history.
949     * @apiSuccess {Boolean} showRating Indicates if the rating should be shown.
950     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation data.
951     * @apiSuccess {Number} reserveAndCancel.reserved The number of reserved lessons.
952     * @apiSuccess {Number} reserveAndCancel.cancelled The number of cancelled lessons.
953     * @apiSuccess {Number} lessonHistoryCount The count of lesson history.
954     * @apiSuccess {Object} latestUserLesson The latest user lesson information.
955     * @apiSuccess {String} latestUserLesson.id The ID of the latest user lesson.
956     * @apiSuccess {String} latestUserLesson.date The date of the latest user lesson.
957     * @apiSuccess {Object} teacherRates The teacher rates.
958     * @apiSuccess {Number} teacherRates.rate The rate of the teacher.
959     * @apiSuccess {String} teacherIdCheck The teacher ID check.
960     * @apiSuccess {String} latestLessonData The latest lesson data.
961     * @apiSuccess {String} teacherLastLogin The last login time of the teacher.
962     * @apiSuccess {Number} teacherFavoriteCount The favorite count of the teacher.
963     * @apiSuccess {Object} teacherFeatures The teacher features.
964     * @apiSuccess {String} teacherFeatures.feature The feature of the teacher.
965     * @apiSuccess {Boolean} validCampaignDate Indicates if the campaign date is valid.
966     * @apiSuccess {Object} campaign The campaign information.
967     * @apiSuccess {String} campaign.id The ID of the campaign.
968     * @apiSuccess {String} campaign.name The name of the campaign.
969     * @apiSuccess {Object[]} ownReservationTeacherData The own reservation teacher data.
970     * @apiSuccess {String} ownReservationTeacherData.id The ID of the reservation.
971     * @apiSuccess {String} ownReservationTeacherData.date The date of the reservation.
972     * @apiSuccess {Number} studentDelayInSeconds The delay in seconds for the student lesson priority.
973     * @apiSuccess {Number} remainingSeconds The remaining seconds for the lesson.
974     * @apiSuccess {Boolean} ownReservationFlg Indicates if the user has their own reservation.
975     * @apiSuccess {String} teacherStatusColor The color of the teacher status.
976     * @apiSuccess {String} chatHash The chat hash.
977     * @apiSuccess {Boolean} liveLessonFlg Indicates if the lesson is a live lesson.
978     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
979     *
980     * @apiSuccessExample {json} Success-Response:
981     *     {
982     *         "teacher": {
983     *             "id": "123",
984     *             "name": "John Doe",
985     *             "image": "http://example.com/image.jpg"
986     *         },
987     *         "country": {
988     *             "name": "Japan",
989     *             "code": "JP"
990     *         },
991     *         "timezone": {
992     *             "name": "JST",
993     *             "offset": "+09:00"
994     *         },
995     *         "tutorCategory": {
996     *             "name": "English"
997     *         },
998     *         "timeDiff": 0,
999     *         "onair": {
1000     *             "id": "456",
1001     *             "status": "active"
1002     *         },
1003     *         "userId": "123",
1004     *         "series": [
1005     *             {
1006     *                 "id": "1",
1007     *                 "name": "Series 1"
1008     *             }
1009     *         ],
1010     *         "teacherTbRatings": [
1011     *             {
1012     *                 "id": "1",
1013     *                 "rating": "5"
1014     *             }
1015     *         ],
1016     *         "historyYear": 2,
1017     *         "historyMonth": 6,
1018     *         "teacherStatus1": {
1019     *             "status": "available"
1020     *         },
1021     *         "oOnair": {
1022     *             "id": "789",
1023     *             "status": "active"
1024     *         },
1025     *         "teacherTitleThreshold": 0,
1026     *         "initialTeacherStatus": 1,
1027     *         "isFav": true,
1028     *         "isHide": false,
1029     *         "unsupportedBrowser": false,
1030     *         "canReport": true,
1031     *         "hideLimitedPlanReservation": false,
1032     *         "firstTimeLoggedIn": false,
1033     *         "paidParent": false,
1034     *         "velifyCount": 1,
1035     *         "countryCodes": [
1036     *             {
1037     *                 "code": "JP",
1038     *                 "name": "Japan"
1039     *             }
1040     *         ],
1041     *         "userCountry": {
1042     *             "name": "Japan",
1043     *             "code": "JP"
1044     *         },
1045     *         "deviceNotSupported": false,
1046     *         "userLang": {
1047     *             "name": "Japanese",
1048     *             "code": "ja"
1049     *         },
1050     *         "getCRData": {
1051     *             "country": "Japan"
1052     *         },
1053     *         "residenceData": {
1054     *             "city": "Tokyo"
1055     *         },
1056     *         "residenceFlg": true,
1057     *         "login": true,
1058     *         "preset": {
1059     *             "id": "1",
1060     *             "name": "Preset Textbook"
1061     *         },
1062     *         "presetIsLiveTextbook": true,
1063     *         "apologyList": [],
1064     *         "isNormalLitePlanUser": true,
1065     *         "getKeepMemo": {
1066     *             "id": "1",
1067     *             "memo": "This is a memo."
1068     *         },
1069     *         "textbookConnectId": "123",
1070     *         "textbookCategoryTypeId": 1,
1071     *         "highLightFlag": true,
1072     *         "liveCoin": 100,
1073     *         "order": 0,
1074     *         "lesson_history_data": [
1075     *             {
1076     *                 "id": "1",
1077     *                 "date": "2023-12-01"
1078     *             }
1079     *         ],
1080     *         "showRating": true,
1081     *         "reserveAndCancel": {
1082     *             "reserved": 10,
1083     *             "cancelled": 2
1084     *         },
1085     *         "lessonHistoryCount": 10,
1086     *         "latestUserLesson": {
1087     *             "id": "1",
1088     *             "date": "2023-12-01"
1089     *         },
1090     *         "teacherRates": {
1091     *             "rate": 5
1092     *         },
1093     *         "teacherIdCheck": "123",
1094     *         "latestLessonData": "2023-12-01 (Fri)",
1095     *         "teacherLastLogin": "01/12/2023 (Fri)",
1096     *         "teacherFavoriteCount": 50,
1097     *         "teacherFeatures": {
1098     *             "feature": "Friendly"
1099     *         },
1100     *         "validCampaignDate": true,
1101     *         "campaign": {
1102     *             "id": "1",
1103     *             "name": "Campaign 1"
1104     *         },
1105     *         "ownReservationTeacherData": [
1106     *             {
1107     *                 "id": "1",
1108     *                 "date": "2023-12-01"
1109     *             }
1110     *         ],
1111     *         "studentDelayInSeconds": 0,
1112     *         "remainingSeconds": 0,
1113     *         "ownReservationFlg": true,
1114     *         "teacherStatusColor": "green",
1115     *         "chatHash": "abc123",
1116     *         "liveLessonFlg": true,
1117     *         "lessonRequestFlg": 1
1118     *     }
1119     *
1120     * @apiError {String} status The status of the request (NG).
1121     * @apiError {String} message The error message.
1122     *
1123     * @apiErrorExample {json} Error-Response:
1124     *     {
1125     *         "status": "NG",
1126     *         "message": "Invalid request."
1127     *     }
1128     * 
1129     * @apiSampleRequest off
1130     */
1131    public function detail($teacherId = null, $highLightFlag = null) {
1132
1133        if (is_null($teacherId)) {
1134            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
1135        }
1136
1137        if (isset($this->request->query['emergency']) && !$this->isStudySapuriTosUser) {
1138            return $this->redirect(myTools::getUrl() . '/waiting');
1139        }
1140
1141        //set mobile view
1142        if (myTools::defaultAction($this) || (isset($_GET['classViewTeacher']) && $_GET['classViewTeacher'] == 1)) {
1143            return $this->spDetail($teacherId);
1144        }
1145        $counselorParams = array(
1146            'type' => 'count',
1147            'args' => array(
1148                'conditions' => array(
1149                    'id' => $teacherId,
1150                    'counseling_flg' => 1
1151                ),
1152                'recursive' => -1
1153            )
1154        );
1155
1156        // - NC-3802: redirect to mypage if counselor teacher
1157        if ($this->Teacher->getTeachers($counselorParams)) {
1158            return $this->redirect('/mypage');
1159        }
1160
1161        $customer_support_flg = $this->TeacherDetail->isCustomerSupportTeacher($teacherId);
1162        //NJ-36255 - redirect to  customer support page if customer support teacher
1163        if($customer_support_flg){
1164            return $this->redirect('/customersupport_detail');
1165        }
1166        
1167        //NJ-65055: params for checking teacher is hidden
1168        $isTeacherHiddenParams = array(
1169            'user_id' => $this->Auth->user('id'),
1170            'teacher_id' => $teacherId
1171        );
1172
1173        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
1174            return $this->redirect('/waiting');
1175        }
1176
1177        // - NC-7031: redirect avatar
1178        $avatarData = $this->isAvatar($teacherId);
1179        if ($avatarData) {
1180            $getAId = $avatarData;
1181            return $this->redirect('/avatar_detail/'.$getAId);
1182        }
1183
1184        //redirect to proper profile
1185        $this->checkProperProfile($teacherId);
1186
1187        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
1188        $queryCondition = array(
1189            'fields' => array(
1190                    'TeacherRankCoin.coins',
1191                    'TeacherRankCoin.reserve_coin_settings_flg',
1192                    'LessonOnair.id',
1193                    'LessonOnair.teacher_id',
1194                    'LessonOnair.user_id',
1195                    'TeacherRankCoin.limited_plan_reservation'
1196                ),
1197            'joins' => array(
1198                array(
1199                    'type' => 'LEFT',
1200                    'table' => 'teacher_rank_coins',
1201                    'alias' => 'TeacherRankCoin',
1202                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
1203                )
1204            ),
1205            'conditions' => array(
1206                array('Teacher.id' => $teacherId)
1207            ),
1208            'show' => 'first'
1209        );
1210
1211        $commonTeacherStatusParams = array(
1212            'page_display' => 'listTeacher',
1213            'query_conditions' => $queryCondition
1214        );
1215        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
1216
1217        if (!$data) {
1218            return $this->redirect('/waiting/');
1219        }
1220
1221        if (in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
1222            return $this->redirect('/mypage');
1223        }
1224        // NJ-51 : Set delay for student lesson priority group
1225        $studentDelayInSeconds = 0;
1226        $standbyStatus = false;
1227        $remainingSeconds = 0;
1228        $chatHash = $this->request->query('chatHash') ?? null;
1229
1230        if( isset($data['LessonOnair']) && $data['LessonOnair'] ) {
1231            $loAir = $data['LessonOnair'];
1232            if( (isset($loAir['status']) && $loAir['status'] == 1) ) {
1233                $standbyStatus = true;
1234            }
1235        }
1236
1237        if( isset($data['TeacherStatus']) && $data['TeacherStatus'] && $data['TeacherStatus']['teacher_status'] == 2 ) {
1238            $tstatus = $data['TeacherStatus'];
1239            if( isset($tstatus['created']) && $tstatus['created'] ) {
1240                if( isset($data[0]['teacher_status_standby_duration']) && $data[0]['teacher_status_standby_duration'] ) {
1241                    if( (int)$data[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
1242                        $remainingSeconds = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$data[0]['teacher_status_standby_duration'];
1243                    }
1244                }
1245                $studentDelayInSeconds = (int) $remainingSeconds * 1000;
1246            }
1247        }
1248
1249        //- check lesson type
1250        $liveLessonFlg = isset($data['LessonOnair']['live_lesson_flg']) ? $data['LessonOnair']['live_lesson_flg'] : 0;
1251
1252        //-get userid
1253        $userId = isset($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : $this->Auth->user('id');
1254
1255        $ownReservationFlg = 0;
1256        if ( $userId ) {
1257            $teacherStatusColor = '';
1258            $teacherObj = new TeacherTable($data['Teacher']);
1259            $tsObj = new TeacherStatusTable($data['TeacherStatus']);
1260
1261            // get reservation
1262            $nextReservation = LessonScheduleTable::getReservation(array(
1263                'LessonSchedule.teacher_id' => $teacherObj->id,
1264                'LessonSchedule.user_id' => $userId
1265            ));
1266        
1267
1268            //-- if user cannot use live lesson -> force to disabled live lesson flag
1269            if ( isset($data['LessonOnair']['live_lesson_flg']) && empty($allowLiveLesson) ) {
1270                $data['LessonOnair']['live_lesson_flg'] = 0;
1271            }
1272
1273            $loStatusParams = array(
1274                'LessonOnair' => $data['LessonOnair'],
1275                'Teacher' => $data['Teacher'],
1276                'TeacherStatus' => $tsObj,
1277                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
1278                'userId' => $userId
1279            );
1280            $teacherStatus = LessonOnairTable::teacherStatusColor($loStatusParams);
1281            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatus);
1282            if( $teacherStatus == '5' ) {
1283                $ownReservationFlg = 1;
1284            }
1285
1286            // - user callan unli option flg
1287            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
1288
1289            // - user native unli option flg
1290            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
1291
1292            $can_use_callan_option = 0;
1293            if($callan_option || $native_option) {
1294                $can_use_callan_option = 1;
1295            }
1296
1297            $this->set('can_use_callan_option', $can_use_callan_option);
1298
1299            // - teacher callan unli option flg
1300            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
1301            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
1302            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
1303            
1304            // - check if has callan badge
1305            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
1306            $this->set('teacher_callan_badge', $teacher_callan_badge);
1307        }
1308
1309        //-default
1310        $liveStatus = 0;
1311
1312        //- fetch live waiting reservation
1313        $waitingReservationLive = [];
1314        if ($this->Auth->loggedIn() && $liveLessonFlg) {
1315            //- fetch user reservation
1316            $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($userId);
1317
1318            if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
1319                $liveStatus = 0;
1320            } else {
1321                //- if lesson started
1322                if (
1323                    !is_null($data['LessonOnair']['connect_id']) &&
1324                    !is_null($data['LessonOnair']['user_id'])
1325                ) {
1326                    if ($data['LessonOnair']['user_id'] == $userId) {
1327                        $liveStatus = 4;
1328                    } else {
1329                        //- check live status
1330                        $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
1331                            'user_id' => $userId,
1332                            'chat_hash' => $data['LessonOnair']['chat_hash']
1333                        ]);
1334
1335                        //-- override status to watch
1336                        if ($liveStatus == 1) {
1337                            $liveStatus = 2; //view live
1338                        }
1339                    }
1340                } else {
1341                    $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
1342                        'teacher_id' => $teacherId
1343                    ]);
1344
1345                    //-has reservation
1346                    if ($waitingReservationLive) {
1347                        if ($waitingReservationLive['LessonSchedule']['user_id'] == $userId) {
1348                            $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
1349                        } else {
1350                            $liveStatus = 1; //live will start
1351                        }
1352                    }
1353                }
1354            }
1355        }        
1356
1357        //redirect if withdrawn teacher
1358        if ($data['Teacher']['status'] <> 1 || $data['Teacher']['inactive_flg'] == 1) {
1359            if ($this->Auth->loggedIn()) {
1360                return $this->redirect(myTools::geturl() . '/mypage');
1361            } else {
1362                return $this->redirect(myTools::geturl() . '/waiting');
1363            }
1364        }
1365
1366        if (isset($data['LessonOnair'])) {
1367            $tmp = (object) $data['LessonOnair'];
1368            if (!$tmp->id) {
1369                $data['LessonOnair'] = null;
1370            }
1371        }
1372
1373        // get teacher information
1374        $teacher = new TeacherTable($data['Teacher']);
1375        $country = new TeacherTable($data['CountryCode']);
1376        $timezone = new TimezoneTable($data['Timezone']);
1377        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
1378
1379        $timeDiff = 0;
1380        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
1381            $timeDiffData = $this->Timezone->computeTimeDiff(array(
1382                'continent_id' => $timezone->continent_id,
1383                'city' => $timezone->city_eng
1384            ));
1385
1386            //
1387            if ($timeDiffData['success']) {
1388                $timeDiff = $timeDiffData['timeDiff'];
1389            }
1390        }
1391
1392        $onair = $data['LessonOnair'];
1393        $onairDataArr = isset($data['LessonOnair']) && $data['LessonOnair'] ? $data['LessonOnair'] : array();
1394
1395        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
1396
1397        $fieldArr = array(
1398            'TextbookCategory.name',
1399            'TextbookCategory.id',
1400            'TextbookCategory.type_id',
1401            'TeacherBadge.textbook_category_id',
1402            'TeacherBadge.badge_flg',
1403            'TextbookCategory.type_id',
1404            'TextbookCategory.image_big_url'
1405        );
1406        $joinArr = array(
1407            array(
1408                'table' => 'teacher_badges',
1409                'alias' => 'TeacherBadge',
1410                'type' => 'LEFT',
1411                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $teacherId)
1412            )
1413        );
1414
1415        // if the user's language is zh-tw, display chinese textbook badge name
1416        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
1417            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
1418            if($langId){
1419                $joinArr[] = array(
1420                    'type' => 'LEFT',
1421                    'table' => 'global_textbook_categories',
1422                    'alias' => 'GlobalTextbookCategory',
1423                    'conditions' => array(
1424                        'GlobalTextbookCategory.language_id' => $langId,
1425                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
1426                    )
1427                );
1428                $this->TextbookCategory->virtualFields = array(
1429                    'gl_name' => 'GlobalTextbookCategory.gl_name'
1430                );
1431                $fieldArr[] = 'gl_name';
1432            }
1433        }
1434
1435        $conArr = array(
1436            'TextbookCategory.status' => 1,
1437            'TextbookCategory.type_id' => 2
1438        );
1439
1440        # get studydapuri textbooks
1441        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
1442        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
1443            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
1444            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
1445        } elseif ($this->isStudySapuriTosUser) {
1446            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
1447        } else {
1448            $exCat = Configure::read('all_sapuri_textbook_category_types');
1449            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
1450        }
1451
1452        //NJ-24096: get last reservation textbook type
1453        $reservationTextbookConnectId = "";
1454        if ($userId) {
1455            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true : false;
1456            $lastReservationData = LessonScheduleTable::getLastReservation($this->Auth->user('id'), $sapuriFlg);
1457
1458            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
1459                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
1460            } else {
1461                $this->User->openDBReplica();
1462                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
1463                $this->User->closeDBReplica();
1464                if (empty($checkUserFirstFlg)) {
1465                    $defaultParams = array(
1466                        'user_id' => $userId,
1467                        'lang' => $userData->native_language2 ?? $this->localizeDir,
1468                    );
1469                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
1470                    if ($defaultReservation) {
1471                        $reservationTextbookConnectId = $defaultReservation;
1472                    }
1473                }
1474            }
1475        }
1476        $this->set(compact('reservationTextbookConnectId'));
1477
1478        // NJ-5836
1479        $displayRestrictionParams = array(
1480            'lang' => $this->localizeDir
1481        );
1482
1483        // get display restriction setting
1484        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
1485
1486        // NJ-5836 add condition for display restriction
1487        if(isset($displayRestriction['field']) && $displayRestriction['field']){
1488            // set condition for display restriction
1489            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
1490        }
1491
1492        //get series and badge
1493        $series = $this->TextbookCategory->find('all', array(
1494            'fields' => $fieldArr,
1495            'conditions' => $conArr,
1496            'joins' => $joinArr,
1497            'order' => array(
1498                'TextbookCategory.sort' => 'ASC'
1499            )
1500        ));
1501
1502        $this->set('series', $series);
1503        myTools::initializeApiTunnel(array('TeachersDetailController'));
1504        $teachersDetail = new TeachersDetailController();
1505
1506        $teacherTbRatings = array();
1507        
1508        if (isset($series) && is_array($series) && count($series) > 0) {
1509            foreach($series as $books){            
1510                $categoryId = $books['TextbookCategory']['id'];
1511                $params = array(
1512                    'teacher_id' =>  (int) $teacherId,
1513                    'textbook_category_id' => (int) $categoryId,
1514                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
1515                );
1516                $teachersDetail->params = $params;        
1517                $decodeResp = json_decode($teachersDetail->teacherTextbookRating());
1518                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
1519            }
1520        }
1521
1522        $this->set('teacherTbRatings', $teacherTbRatings);
1523
1524        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
1525
1526        $this->set('historyMonth',$historyMonth);
1527        $this->set('historyYear',$historyYear);
1528
1529        //teacher_status if login or break
1530        $teacherStatus1 = $this->TeacherStatus->find('first', array(
1531            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
1532            'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
1533        ));
1534
1535        //lesson onair
1536        if (!empty($onair)) {
1537            $oOnair = new LessonOnairTable($onair);
1538        } else {
1539
1540            if (!empty($teacherStatus1)) {
1541                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
1542            } else {
1543                $oOnair = 0;
1544            }
1545        }
1546
1547        // NJ-17264
1548        $teacherTitleThreshold = 0;
1549        if(isset($data['TitleThresholdTeacher']['title_type'])){
1550            $teacherTitleThreshold = $data['TitleThresholdTeacher']['title_type'];
1551        }
1552
1553        // inital teacher status
1554        $initialTeacherStatus = isset($teacherStatus1['TeacherStatus']) && $teacherStatus1['TeacherStatus']['status'] ? $teacherStatus1['TeacherStatus']['status'] : 0;
1555
1556        //favorite
1557        $where = array(
1558            'UsersFavorite.user_id'     => $this->Auth->user('id'),
1559            'UsersFavorite.teacher_id'     => $teacherId,
1560        );
1561        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
1562
1563        // NC-5897 : check if teacher was hide by user.
1564        $where = array(
1565            'user_id' => $this->Auth->user('id'),
1566            'teacher_id' => $teacherId,
1567        );
1568        $isHide = $this->BlockList->isTeacherHide($where);
1569        $this->User->recursive = -1;
1570        $data = $this->User->findById($userId);
1571        $user = isset($data['User'])?$data['User']: null;
1572        $unsupportedBrowser = false;
1573        $browser =  $this->request->header('User-Agent');
1574
1575        if (preg_match('/(Edg|Edge)/i',$browser) ) {
1576            $unsupportedBrowser = false;
1577        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
1578            $unsupportedBrowser = true;
1579        }
1580        $canReport = true;
1581        if ($user) {
1582            $userData = new UserTable($data['User']);
1583            $userMembership = $userData->getUserMembership();
1584            $this->set('user_lang', $userData->native_language2);
1585            // if weekly plan user
1586            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
1587            $corporateUser = isset($corporateType) ? $corporateType : '';
1588
1589            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
1590            $canReport = $userData->getMembershipTypeIndex();
1591            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
1592        }
1593        $this->set('unsupportedBrowser', $unsupportedBrowser);
1594        // NC-6615 check if user can report the teacher
1595        $this->set('canReport', $canReport);
1596
1597        $hideLimitedPlanReservation = false;
1598        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
1599            $hideLimitedPlanReservation = true;
1600        }
1601
1602        $firstTimeLoggedIn = false;
1603        if (empty($user['last_login_time'])) {
1604            $firstTimeLoggedIn = true;
1605        }
1606
1607        $paidParent = false;
1608
1609        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
1610            'conditions' => array(
1611                'user_id' => $this->Auth->user('id'),
1612                'status' => 0
1613            )
1614        ));
1615
1616        $countryCodes = $this->CountryCode->find('all',array(
1617            'fields' => array(
1618                'code',
1619                'country_name'
1620            ),
1621            'order' => 'country_name ASC'
1622        ));
1623        $this->set('countryCodes',$countryCodes);
1624
1625        $userCountry['CountryCode']['country_name'] = '';
1626        $userCountry['CountryCode']['code'] = '';
1627        if(!empty($data['User']['country_code'])){
1628            $userCountry = $this->CountryCode->find('first',array(
1629                'conditions' => array(
1630                    'code' => $data['User']['country_code']),
1631                'fields' => array(
1632                    'code',
1633                    'country_name')
1634            ));
1635            if(empty($userCountry)){
1636                $userCountry['CountryCode']['code'] = '';
1637            }
1638        }
1639        $this->set('countryCodes',$countryCodes);
1640
1641        //check if user is child by checking its parent id not empty
1642        if (isset($data['User']['parent_id'])) {
1643            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
1644        }
1645        #$lesson_count=0;
1646        // 管理者権限会員は無制限でレッスン出来る
1647        if (isset($user['admin_flg']) && $user['admin_flg']=='1') {
1648            $user['charge_flg'] = 1;
1649            $lesson_count=0;
1650            $lesson_count_today = 0;
1651        }
1652
1653        if (empty($user['enquate6'])) {
1654            $user['enquate6'] = '1';
1655        }
1656
1657        if (empty($user['enquate7'])) {
1658            $user['enquate7'] = '1';
1659        }
1660
1661        // if tos user
1662        if (isset($this->sharedUserData['UsersExtend']['id'])) {
1663            $user['tos_user'] = true;
1664        }
1665
1666        //number of stusap lesson
1667        $stusapLessonCount = (int)$teacher->stusap_lesson_count + (int)$teacher->stasapu_tos_lesson_count;
1668        //number of lesson
1669        $lessonCount = (int)$teacher->lesson_count;
1670
1671        // - prepare head text
1672        $headTextWD = $pageTitleWD = $teacher->name;
1673        $metaDescWD = "";
1674        if ($this->localizeDir == Configure::read('default.user_language')) {
1675            $headTextWD .= '('.$teacher->jp_name.')';
1676            $pageTitleWD .=  '('.$teacher->jp_name.')';
1677            //$metaDescWD .= '('.$teacher->jp_name.')';
1678        }
1679
1680        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
1681            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').': '.$lessonCount . ' ' . lcfirst(($lessonCount <= 1 ?  __dx('waiting', 'singular', '回') :  __d('waiting', '回'))); 
1682        } else { // if the language is not Custom language format
1683            $headTextWD .= '&ensp;'. __d('waiting','レッスン数').':'.$lessonCount. __d('waiting','回');
1684        }
1685        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
1686        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
1687
1688        //prepare meta image 
1689        $_teacherImgUrl = $teacher->getImageUrl();
1690
1691        //check if teacher has no image 
1692        if (empty($teacher->image_url) || !$teacher->image_url) {
1693            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
1694            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
1695        }
1696
1697
1698        // - set page meta information
1699        $this->set('headtext', $headTextWD);
1700        $this->set('title_for_layout', $pageTitleWD);
1701        // $this->set('meta_description', $metaDescWD);
1702        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
1703        $this->set('counselingFlg',$teacher->counseling_flg);
1704        $this->set('meta_teacher_img',$_teacherImgUrl);
1705
1706        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
1707        $options['language_id'] = $reviewLanguage[0] ?? null;
1708        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
1709
1710        $userTable = new UserTable($this->Auth->user());
1711        $sapuriPlan = $userTable->isStudySapuri();
1712        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
1713        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
1714            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
1715        } else {
1716            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
1717        }
1718        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId , $options);
1719        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
1720
1721        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
1722        $get_weekly_rating['TeacherWeeklyRating']['averageRate'] ??= '';
1723        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
1724            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) {
1725                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = number_format($get_weekly_rating['TeacherWeeklyRating']['averageRate'], 2, ',', '');
1726            } else {
1727                $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
1728            }
1729        }
1730
1731        /* -- NC-5293 start -- */
1732        $this->loadModel('Translation');
1733        $translationCategories = Configure::read('translation_categories');
1734        $translateParams = array(
1735            'languageCode' => $this->lang_iso,
1736            'categoryId' => $translationCategories['teacher_message'],
1737            'messageId' => $teacher->id,
1738            'text' => $teacher->message
1739        );
1740
1741        $translatedMessageParams = $translateParams;
1742        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
1743        $translateParams['text'] = $teacher->self_introduction_third_pp;
1744        $translatedSelfIntroductionThirdPpParams = $translateParams;
1745        /* -- NC-5293 end -- */
1746
1747        // Translate and save translated data
1748        $globalTranslate = TeacherTable::translate(array(
1749            'id' => $teacherId,
1750            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
1751            'controller' => static::class
1752        ));
1753        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
1754        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
1755        $this->set('message', $translatedMessageTranslation);
1756        $this->set('intro', $translatedThirdppTranslation);
1757
1758        //find the selfintro 
1759        $TeacherTable = new TeacherTable($teacher);
1760        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
1761        $_userSelfIntro = strip_tags($_userSelfIntro); 
1762
1763        //set the new meta description
1764        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
1765        $this->set('meta_description', $metaDescWD);
1766
1767        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($data['User']['payment_plan_id']);
1768        $canCoinPurchase = true;
1769        if (isset($data['User']['corporate_id']) && isset($corporateType)) {
1770            if (in_array($corporateType, array(Configure::read('corporate_type.standard'), Configure::read('corporate_type.premium')))) {
1771                $canCoinPurchase = true;
1772            } else {
1773                $canCoinPurchase = false;
1774            }
1775        }
1776
1777        //
1778        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
1779
1780        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
1781        $coinParams =  array(
1782            'current_rank_id' => $teacherCurrentRankId,
1783            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
1784            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
1785            'student_native_option' => $userData->native_option,
1786            'home_flg' => $teacher->home_flg,
1787            'counseling_flg' => $teacher->counseling_flg,
1788            'avatar_parent_flg' => $teacher->avatar_parent_flg,
1789            'avatar_flg' => $teacher->avatar_flg,
1790            'native_speaker_flg' => $teacher->native_speaker_flg
1791        );
1792
1793        // get teacher coin settings
1794        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
1795
1796        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
1797        $displayNativeOptionAmountFlg = false;
1798        if($teacherCoinData){
1799            // set teacher reservation coin
1800            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
1801            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
1802            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
1803            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
1804        }
1805        $teacherCoin = $teacherCoin ?? 0;
1806        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
1807
1808        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
1809
1810        $sapuriCoin = 0;
1811        if ($this->isStudySapuriUser) {
1812            $teacherParams = array(
1813                'teacher_id' => $teacher->id,
1814                'current_rank_id' => $teacherCurrentRankId
1815            );
1816            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
1817        }
1818
1819        $ongoingLessonWithOtherStudentButtonDelay = 0;
1820        if($onairDataArr){
1821            if( 
1822                (isset($onairDataArr['user_id']) && $onairDataArr['user_id'] != $userId) && 
1823                (isset($onairDataArr['status']) && $onairDataArr['status'] == '3') && 
1824                (int)$this->studentLessonPriorityTimeDelayInSeconds > 0
1825            ) {
1826                $ongoingLessonWithOtherStudentButtonDelay = 1;
1827            }    
1828        }
1829    
1830        // set lesson review modal on/off
1831        $this->set('lesson_review_flg', $data['User']['lesson_review_flg']);
1832        $where = array(
1833            'UsersFavorite.teacher_id' => $teacherId,
1834        );
1835
1836        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
1837        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $isFav? [$teacher->id]: []]);
1838        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
1839            'favIds' => $isFav? [$teacher->id]: [],
1840            'favIdsTeacherCategory' => $teacherFavColor
1841        ]);
1842        
1843        // NJ-3696
1844        $this->LessonOnairsLog->openDBReplica();
1845        $textbook = $this->LessonOnairsLog->find('first', array(
1846            'fields' => array(
1847                'TextbookCategories.id',
1848                'TextbookCategories.textbook_category_type'
1849            ),
1850            'joins' => [
1851            [
1852                'table' => 'textbook_connects',
1853                'alias' => 'TextbookConnects',
1854                'type' => 'left',
1855                'conditions' => ["TextbookConnects.id = LessonOnairsLog.connect_id"]
1856            ],
1857            [
1858                'table' => 'textbook_categories',
1859                'alias' => 'TextbookCategories',
1860                'type' => 'left',
1861                'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1862            ]
1863        ],
1864            'conditions' => array('LessonOnairsLog.chat_hash' => $chatHash),
1865            'recursive' => -1
1866        ));
1867        $this->LessonOnairsLog->closeDBReplica();
1868    
1869        if(!$textbook){
1870            $this->LessonOnair->openDBReplica();
1871            $textbook = $this->LessonOnair->find('first', array(
1872                'fields' => array(
1873                    'TextbookCategories.id',
1874                    'TextbookCategories.textbook_category_type'
1875                ),
1876                'joins' => [
1877                    [
1878                        'table' => 'textbook_connects',
1879                        'alias' => 'TextbookConnects',
1880                        'type' => 'left',
1881                        'conditions' => ["TextbookConnects.id = LessonOnair.connect_id"]
1882                    ],
1883                    [
1884                        'table' => 'textbook_categories',
1885                        'alias' => 'TextbookCategories',
1886                        'type' => 'left',
1887                        'conditions' => ['TextbookCategories.id = TextbookConnects.category_id']
1888                    ]
1889                ],
1890                'conditions' => array('LessonOnair.chat_hash' => $chatHash),
1891                'recursive' => -1
1892            ));
1893            $this->LessonOnair->closeDBReplica();
1894        }
1895
1896        //NJ-20590
1897        $teacher->image_url = myTools::checkAndReturnPresignedUrl($teacher->image_url);
1898
1899
1900        $hash = $this->request->query['chatHash'] ?? null;
1901        if(!empty($hash)){
1902            if (!class_exists('myMemcached')) {
1903                App::uses('myMemcached', 'Lib');
1904            }
1905            $memcached = new myMemcached();
1906            $appreciationDoneCache = $memcached->get("appreciation_done_".$hash);
1907            $this->set("isAppreciationDone", $appreciationDoneCache == 1 ? 1 : 0);
1908        }
1909
1910        // NJ-NJ-62396
1911        $isCallanTextbook = (!empty($textbook['TextbookCategories']['textbook_category_type']) && in_array($textbook['TextbookCategories']['textbook_category_type'], Configure::read('callan_textbook_type'))) ? 1 : 0;
1912
1913
1914        // NJ-3696
1915        // set view vars
1916        $setData = array(
1917            'textbookCategory' => $textbook['TextbookCategories'] ?? [],
1918            'teacher' => $teacher,
1919            'onair' => $oOnair,
1920            'isFav' => $isFav,
1921            'isHide' => $isHide,
1922            'ongoingLessonWithOtherStudentButtonDelay' => $ongoingLessonWithOtherStudentButtonDelay,
1923            'initialTeacherStatus' => $initialTeacherStatus,
1924            'teacherFavsColors' => $teacherFavsColors,
1925            'favoriteCount' => $favoriteCount,
1926            'tId' => $teacher->id,
1927            'user' => $user,
1928            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
1929            'userMembership' => isset($userMembership)?$userMembership:'',
1930            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
1931            'enquate6_options' => UserTable::getEnquate6(),
1932            'enquate7_options' => UserTable::getEnquate7(),
1933            'stusapLessonCount' => $stusapLessonCount,
1934            'lessonCount' => $lessonCount,
1935            'commentCount' => $commentCount,
1936            'userId' => $userId,
1937            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
1938            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
1939            'callanCoin' => (int)$callanCoin,
1940            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
1941            'isCallanTextbook' => $isCallanTextbook,
1942            'UserData' => $data,
1943            'userCountry' => $userCountry,
1944            'velifyCount' => $velifyCount,
1945            'firstTimeLoggedIn' => $firstTimeLoggedIn,
1946            'isLoggedIn' => $this->Auth->loggedIn(),
1947            'country' => $country,
1948            'timeDiff' => $timeDiff,
1949            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
1950            'translatedMessageParams' => $translatedMessageParams,
1951            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
1952            'translationModel' => $this->Translation,
1953            'weekly_ratings' => isset($get_weekly_rating['TeacherWeeklyRating']) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
1954            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
1955            'canCoinPurchase' => $canCoinPurchase,
1956            'liveStatus' => $liveStatus,
1957            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
1958            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
1959            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
1960            'sapuriCoin' => $sapuriCoin,
1961            'isEmergencyPage' => !empty($this->request->query['emergency']) ? true : false,
1962            'teacherTitleThreshold' => $teacherTitleThreshold,
1963        );
1964
1965        $this->set($setData);
1966        if ($userId) {
1967            $points = $this->UsersPoint->find('first', array(
1968                'fields' => array('point'),
1969                    'conditions' => array(
1970                        'user_id' => $userId
1971                    )
1972                )
1973            );
1974
1975            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
1976            $reservePoint = Configure::read("reserve_point");
1977
1978            if (intval($reservePoint) < 1) $reservePoint = 0;
1979            //set promo discount for reservation
1980            // set paramater to 2 for reservation promo
1981            $bonus = CoinSetTable::getCoinSet(2);
1982            //check if the promo is valid today
1983            if ($bonus) {
1984                $reservePoint = $bonus;
1985            }
1986        } else {
1987            $points = 0;
1988        }
1989
1990        # get user timezone
1991        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
1992        $user_timezone_data = $this->Timezone->find('first',
1993            array(
1994                'fields' => array(
1995                    'Timezone.city_eng',
1996                    'Timezone.utc_offset',
1997                    'Timezone.country_code_id'
1998                ),
1999                'conditions' => array(
2000                    'Timezone.id' => $user_timezone_id
2001                ),
2002                'recursive' => -1
2003            )
2004        );
2005
2006        // - NJ-3653 get country
2007        $countryTimezone = null;
2008        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
2009            // - Get all country Code
2010            $countryOptions = $this->Timezone->countryOptions();
2011
2012            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
2013            $countryName = $countryOptions[$countryCodeId]['country_name'];
2014
2015            if (isset($countryName) && $countryName) {
2016                $countryTimezone = $countryName;
2017            }
2018        }
2019
2020        $this->set('countryTimezone', $countryTimezone);
2021        $this->set('userTimezoneData', $user_timezone_data);
2022
2023        #user time
2024        $datetime = date('Y-m-d H:i:s');
2025        $localTime = $this->displayTime;
2026        // NJ-29496
2027        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
2028            $formattedDate = date('d/m/Y G:i', $localTime);
2029        } else {
2030            $formattedDate = date('Y/m/d G:i', $localTime);
2031        }
2032        $this->set('userCurrentTime', $formattedDate);
2033
2034        $this->set('points', $points);
2035        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
2036
2037        $countrids_no = Configure::read('sms_send.countrids_no');
2038        $this->set('countrids_no', $countrids_no);
2039
2040        $deviceNotSupported = false;
2041        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
2042        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
2043            $deviceNotSupported = true;
2044        }
2045        $this->set('deviceNotSupported', $deviceNotSupported);
2046
2047        $userLang = !empty($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
2048        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
2049        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
2050        $residenceData = $this->getResidenceData($getCRData);
2051        $this->set('residenceData',$residenceData);
2052        $this->set('residenceFlg',$residenceData['countryFlag']);
2053        $this->set('deviceNotSupported', $deviceNotSupported);
2054        $this->set('statusCheck', array(1, 4));
2055
2056        $this->set('login', $this->Auth->loggedIn());
2057        $preset = array();
2058        if($this->Auth->User('id')) {
2059            //get preset textbook -> last viewed -> default textbook category first lesson
2060            $presetParams = array("user_id" => $this->Auth->User('id'));
2061
2062            //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
2063            $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
2064            //add additional parameters
2065            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
2066                $presetParams["lang"] = $this->localizeDir;
2067            }
2068
2069            #NC-9916
2070            if($data['User']) {
2071                $presetParams['native_language2'] = $userData->native_language2;
2072                $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
2073            }
2074
2075            $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
2076            if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
2077                # for preset
2078                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
2079                $presetParams['last_opened_date'] = $preset_data['preset_last_viewed_date'];
2080
2081            } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
2082                # use last viewed textbook if no preset data.
2083                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
2084                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
2085
2086            }
2087
2088            // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
2089            $presetParams['is_pc_flg'] = 1;
2090
2091            # fetch preset
2092            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2093            if(!$preset) {
2094                unset($presetParams['connect_id']);
2095                unset($presetParams['last_opened_date']);
2096                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
2097            }
2098        }
2099
2100        //set variable preset textbook to be displayed
2101        $this->set('preset', $preset);
2102
2103        // NJ-8416: check for textbook live_lesson_flg is ON
2104        $textbookCategory = isset($preset['textbook_info']['TextbookCategory']) ? $preset['textbook_info']['TextbookCategory'] : array();
2105        $presetIsLiveTextbook = (isset($textbookCategory['live_lesson_flg']) && $textbookCategory['live_lesson_flg']) ? true : false;
2106        $this->set('presetIsLiveTextbook', $presetIsLiveTextbook);
2107
2108        // apology list (cancellation of reservation)
2109         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
2110
2111         // -- NJ-18780: is normal lite plan user 
2112        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
2113        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
2114
2115        $this->set('apologyList', $apologyList);
2116        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
2117            'userId' => $this->Auth->user('id'),
2118            'teacherId' => $teacherId,
2119            'timeDiff' => $this->timeDiff,
2120            'isNormalLitePlanUser' => $isNormalLitePlanUser
2121        ));
2122        $this->set('disabledSchedule', json_encode($disabledSchedule));
2123        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
2124        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
2125        $this->set('isNormalLitePlanUser',$isNormalLitePlanUser);
2126
2127        //NC-7603 get keep memo
2128        $getKeepMemo = $this->UsersMemo->find('first', array(
2129            'fields' => array(
2130                'id',
2131                'memo'
2132            ),
2133            'conditions' => array(
2134                'user_id' => $this->Auth->user('id'),
2135                'teacher_id' => $teacherId,
2136                'type' => 0
2137            ),
2138            'order' => array('created DESC'),
2139        ));
2140
2141        $this->set('keep_memo', $getKeepMemo);
2142
2143        // NC-8020
2144        $this->set('textbookConnectId', $preset['textbook_connect_id']);
2145        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
2146
2147        // - NJ-6390 add highLightFlag
2148        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
2149
2150        // NJ-42
2151        $liveCoin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(['current_rank_id' => $teacher->current_rank_id]);
2152        $this->set('liveCoin', number_format((float)$liveCoin));
2153
2154        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
2155        //NC-7984 start
2156        $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir);
2157        if(!empty($lesson_history_data)) {
2158            $this->set('lessonHistory', $lesson_history_data['lessonHistory']);
2159            $this->set('textbookNamesCachedArr', $lesson_history_data['textbookNamesCachedArr']);
2160        }
2161        //NC-7984 end
2162        
2163        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
2164        $this->set('showRating', $showRating);
2165
2166        //NJ-20069 teacher
2167        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
2168        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null);
2169        $lessonHistoryCount  = count($lessonHistory['lessonHistory']);
2170        $latestUserLesson = isset($lessonHistory['lessonHistory'][0]['LessonOnairsLog']) ? $lessonHistory['lessonHistory'][0]['LessonOnairsLog'] : null;
2171        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
2172        
2173        // - if has translated Category name
2174        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
2175            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
2176        }
2177        
2178        $formattedLatestLessonData = "";
2179        if(!empty($latestUserLesson))
2180        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
2181        
2182        $teacherLastLogin = $teacher->last_login_time;
2183        $formattedTeacherLastLogin = "";
2184        if(!empty($teacherLastLogin)) {
2185            if ($this->localizeDir == 'pt-br') {
2186                $daysOfWeekPtBr = [
2187                    'Sun' => __dx('account', 'week', '日'), // Dom
2188                    'Mon' => __dx('account', 'week', '月'), // Seg
2189                    'Tue' => __dx('account', 'week', '火'), // Ter
2190                    'Wed' => __dx('account', 'week', '水'), // Qua
2191                    'Thu' => __dx('account', 'week', '木'), // Qui
2192                    'Fri' => __dx('register', 'week', '金'), // Sex
2193                    'Sat' => __dx('account', 'week', '土')  // Sab
2194                ];
2195                $dayOfWeekPtBr = $daysOfWeekPtBr[date('D', strtotime($teacherLastLogin))];
2196        $formattedTeacherLastLogin = date('d/m/Y', strtotime($teacherLastLogin)) . " ({$dayOfWeekPtBr}";
2197            } else {
2198                $formattedTeacherLastLogin = date('Y-m-d',strtotime($teacherLastLogin)). " (" . date('D',strtotime($teacherLastLogin)) . ") ";
2199            }
2200        }
2201
2202        $this->set('lessonHistoryCount', $lessonHistoryCount);
2203        $this->set('latestUserLesson', isset($lessonHistory['lessonHistory'][0]) ? $lessonHistory['lessonHistory'][0] : null);
2204        $this->set('teacherRates', $reserveAndCancel);
2205        $this->set('teacherIdCheck', $teacherId);
2206        $this->set('latestLessonData', $formattedLatestLessonData);
2207        $this->set('teacherLastLogin', $formattedTeacherLastLogin);
2208        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
2209
2210        $this->TeacherFeature->openDBReplica();
2211        $teacherFeatures = $this->TeacherFeature->find('first', array(
2212            'conditions' =>  array(
2213                'TeacherFeature.teacher_id' => $teacherId
2214            )
2215        ));
2216        $this->TeacherFeature->closeDBReplica();
2217        
2218        # NJ-19429: fetch campaign
2219        $studentID = $this->Auth->user('id');
2220        $inCampaignDetails = $this->CampaignInstructor->getValidateUserCampaign($teacherId, $studentID);
2221
2222        //NJ-47494 - add 8 day checker for campaign
2223        $now = date('Y-m-d');
2224        $dayTimer = date('Y-m-d', strtotime('+7 days'));
2225        
2226        $inCampaignStartDate = isset($inCampaignDetails['CampaignInstructor']['start_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['start_date'])) : null;
2227        $inCampaignEndDate = isset($inCampaignDetails['CampaignInstructor']['end_date']) ? date('Y-m-d', strtotime($inCampaignDetails['CampaignInstructor']['end_date'])) : null;
2228        $validCampaignDate = !($dayTimer < $inCampaignStartDate || $now > $inCampaignEndDate);
2229
2230        if ($inCampaignDetails && $validCampaignDate == 1){
2231            $campaign = $inCampaignDetails['CampaignInstructor'];
2232
2233            $campaignTag = '';
2234            if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
2235                $campaignTag .= $campaign['discount'] == 100 ? '100% OFF ' : '50% OFF ';
2236                $campaignTag .= '(' . __d('waiting',Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]) . ') ';    
2237
2238                // NJ-47838 GGPE FB10
2239                if((int) $campaign['classification'] == 4) {
2240                    $campaignTag = __d('waiting', Configure::read('campaign_instructor_tags')[$campaign['campaign_tag_id']]);
2241                }
2242            } else { // if the language is not Custom language format
2243                $campaignTag .= $campaign['discount'] == 100 ? '100%OFF ' : '50%OFF ';
2244                $campaignTag .= '('.Configure::read('campaign_instructor_textbook_type')[$campaign['textbook_type']]. ') ';
2245                $campaignTag .= Configure::read('campaign_instructor_type')[$campaign['classification']] . '講師';
2246            }
2247
2248            $teacherFeatures['CampaignTag'] = $campaignTag;
2249
2250            // NJ-47838
2251            $teacherFeatures['CampaignTagClassification'] = $campaign['classification'];
2252            // NJ-47838 : Set a flag if the campaign is classified as "Live"
2253            $teacherFeatures['IsCampaignLive'] = ($campaign['classification'] === 4);
2254
2255            // NJ-47838 : Ensure the campaign discount is set if the campaign is live and the teacher is registered for it
2256            if ($teacherFeatures['IsCampaignLive']) {
2257                $teacherFeatures['CampaignLiveDiscount'] = $campaign['discount'];
2258            }
2259        }
2260
2261        if(isset($campaign) && $campaign){
2262            $this->set('campaignDiscount', isset($campaign['discount']) ? $campaign['discount'] : null);
2263            $this->set('campaignTextbook', isset($campaign['textbook_type']) ? $campaign['textbook_type'] : null);
2264            $this->set('campaignDiscountClassification', isset($campaign['classification']) ? $campaign['classification'] : null);
2265        }
2266
2267        $this->set('teacherFeatures', $teacherFeatures);
2268        
2269        // NJ-3786 textbook teacher recommendation
2270        $curDate = date('Y-m-d');
2271        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
2272        $txtTeacherRecommendlimit = 10;
2273        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
2274        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
2275        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
2276
2277        if( $userId ) {
2278            // - NJ-8416: check for last lesson type
2279            $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
2280            $this->log('[NJ-8416 lastLessonType waitingDetail] -> ' . json_encode($lastLessonType), 'debug');
2281            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
2282                'user_id' => $userId,
2283                'limit' => 10, // waiting detail page
2284                'last_lesson_type' => $lastLessonType
2285            ) );
2286            $textbookCategoryId = $lastBookUsedData['category_id'];
2287            $textbookBadge = $lastBookUsedData['textbook_badge'];
2288            $this->log('[NJ-8416 textbookCategoryId waitingDetail] -> ' . json_encode($textbookCategoryId), 'debug');
2289            $paramsArr = array(
2290                'user_id' => $userId,
2291                'begin_date' => $beginDate,
2292                'end_date' => $endDate,
2293                'textbook_category' => $textbookCategoryId,
2294                'textbook_badge' => $textbookBadge,
2295                'limit' => $txtTeacherRecommendlimit,
2296                'user_data' => $userData,
2297                'exclude_teacher_id' => $teacherId
2298            );
2299
2300            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
2301            if( $teacherTextbookStatData ) {
2302                $dataList = $this->arrangeTeacherRecommendList( array( 
2303                        'user_id' => $userId,
2304                        'data' => $teacherTextbookStatData,
2305                        'category_id' => $textbookCategoryId,
2306                        'user_data' => $userData
2307                    ) 
2308                );
2309                $this->set('textbookTeacherData', $dataList);
2310            }
2311        }
2312
2313        $ownReservationTeacherData = $this->LessonSchedule->getWaitingToJoinReservationTeacherInfo( array( 'user_id' => $this->Auth->user('id'), 'limit_checker_flag' => 1 ) );
2314        $this->set( 'ownReservationTeacherId', $ownReservationTeacherData['teacher_id'] ); // live lesson work-around
2315        $this->set( 'lessonScheduleOwnReservationTeacher', isset($lessonScheduleOwnReservationTeacherData['teacher_id']) ? $lessonScheduleOwnReservationTeacherData['teacher_id'] : null ); // live lesson work-around
2316        $this->set( 'studentDelayInSeconds', (int)$studentDelayInSeconds );
2317        $this->set( 'remainingSeconds', (int)$remainingSeconds );
2318        $this->set( 'ownReservationFlg', $ownReservationFlg );
2319        $this->set( 'teacherStatusColor', $teacherStatusColor );
2320
2321        if ($this->request->query('chatHash')) {
2322            $chatHash = $this->request->query('chatHash');
2323
2324            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2325            $this->set('data',  $allData);
2326
2327            $friParams = array(
2328                'type' => 0,
2329                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
2330                'from' => 'user'
2331            );
2332
2333            $strengthItems = $this->FeatureRatingItem->getActiveItems($friParams);
2334
2335            // get active weakness feature rating items
2336            $friParams['type'] = 1;
2337            $weaknessItems = $this->FeatureRatingItem->getActiveItems($friParams);
2338
2339            $this->set('strengthItems', $strengthItems);
2340            $this->set('weaknessItems', $weaknessItems);
2341            
2342            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
2343
2344            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
2345                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
2346
2347                if(!$allData) {
2348                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
2349                }
2350            }
2351
2352            $this->set('data',  $allData);
2353
2354            $live_lesson_viewer = 0;
2355            if((!empty($allData['LessonOnairsLog']) && $allData['LessonOnairsLog']['live_lesson_flg'] == 1 && $allData['LessonOnairsLog']['user_id'] != $userId)
2356                || (!empty($allData['LessonOnair']) && $allData['LessonOnair']['live_lesson_flg'] == 1 && $allData['LessonOnair']['user_id'] != $userId)
2357            ) { $live_lesson_viewer = 1; }
2358            
2359            // get last feature rating items
2360            if($live_lesson_viewer){
2361                $lastRatingItems = $this->ViewerFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2362            } else {
2363                $lastRatingItems = $this->UserFeatureRatingLastVoted->getLastEvalItems(array('teacherId' => $teacherId, 'userId' => $userId));
2364            }
2365            
2366            $this->set('lastSelectedStrengthItems', isset($lastRatingItems['strengthItems']) ? $lastRatingItems['strengthItems'] : array());
2367            $this->set('lastSelectedWeaknessItems', isset($lastRatingItems['weaknessItems']) ? $lastRatingItems['weaknessItems'] : array());
2368
2369            $userValidForSSBEDT = false;
2370            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
2371                $userValidForSSBEDT = true;
2372            }
2373            $param = array(
2374                "user_id" => $userId,
2375                "select_method" => "first",
2376                "env_flag" => "all",
2377                'connect_id' => $allData['Connect']['id'],
2378                "user_locale" => $this->localizeDir,
2379                "userValidForSSBEDT" => $userValidForSSBEDT
2380            );
2381            //NJ-12326
2382            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
2383                $corporateParams = array('user_id' => $userId);
2384                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
2385                
2386                if ($corporateTextbookControlFlg == 1) {
2387                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
2388                    if (!empty($categoryData)) {
2389                        $param['include_kids_category'] = $allData['Connect']['category_id'];
2390                    }
2391                }
2392            }
2393            $textbookData = $this->Textbook->getTextbooks($param);
2394            $data = $textbookData['res_data'];
2395
2396            $isReservedLesson = 2;
2397            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
2398            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
2399            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
2400            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
2401            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
2402
2403            //NJ-3626 Optimize PC /lesson-finish page
2404            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
2405            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
2406                $lessonOnairLatestDataFlg = true;
2407                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
2408                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
2409            } else {
2410                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
2411                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
2412                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
2413                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
2414                }
2415            }
2416
2417            // - initialize empty variable
2418            $isLatestPresetTextbookMadeDuringLastLesson = [];
2419            $latestPresetTextbookParams = [];
2420
2421            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
2422            if ($lessonOnairLatestDataFlg) {
2423                $latestPresetTextbookParams = array (
2424                    'userId' => $userId,
2425                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2426                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
2427                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
2428                );
2429
2430            // - if has lesson onairs log
2431            } else if ($lessonOnairLogsLatestData) {
2432                $latestPresetTextbookParams = array (
2433                    'userId' => $userId,
2434                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
2435                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
2436                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
2437                );
2438
2439            }
2440            
2441            // - if has parameters for fetching latest textbook parameters
2442            if ($latestPresetTextbookParams) {
2443                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
2444            }
2445
2446            // -  check sapuri ID
2447            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
2448                if (isset($lessonOnairLatestDataFlg)) {
2449                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2450                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
2451                    ) {
2452                        $hideTextbookChangeModal = 'true';
2453                    }
2454                } else {
2455                    if (
2456                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
2457                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
2458                    ) {
2459                        $hideTextbookChangeModal = 'true';
2460                    }
2461                }
2462            }
2463
2464            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
2465
2466            $this->set('hideTextbookChangeModal', $hideTextbookChangeModal);
2467
2468            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
2469            if (
2470                $hideTextbookChangeModal == 'false'
2471                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
2472                && (isset($onGoingLesson) && $onGoingLesson == false)
2473            ) {
2474                $allTextbookParams = array(
2475                    'category_id' => $latestPresetTextbookConnect_categoryId, 
2476                    'connect_id' => $latestPresetTextbookConnect_id,
2477                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
2478                );
2479                
2480                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
2481                // if has next textbook chapter, show button 
2482                if (
2483                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
2484                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
2485                ) {
2486                    $enableNextTextbookChapterButton = 'true';
2487                }
2488            }
2489
2490            if(!empty($this->sharedUserData['User'])){
2491                // - campaing stamps
2492                $this->getActiveCampaignStampData();
2493            }
2494
2495            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
2496        }
2497
2498        //NJ-18780 : check the user total reservation if lite plan 
2499        $_user = $this->sharedUserData['User'] ?? array();
2500        $liteLimitReservationFlg = 0;
2501
2502        if (
2503            $_user && 
2504            in_array($_user['payment_plan_id'], Configure::read('lite_payment_plans'))
2505        ) {
2506            # fetch the total reservation 
2507            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $this->Auth->user('id')));
2508
2509            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
2510                # show modal
2511                $liteLimitReservationFlg = 1;
2512            }
2513        }
2514
2515        // NJ-18780 : set view 
2516        $this->set('liteLimitReservationFlg',$liteLimitReservationFlg);
2517
2518
2519        $this->set('chatHash', isset($chatHash) ? $chatHash : '');
2520    
2521        //-Live Lesson Phase 3
2522        $this->set('liveLessonFlg', $liveLessonFlg);
2523
2524        //NJ-33414
2525        $this->UsersDetail->openDBReplica();
2526        $fetchUsersDetail = $this->UsersDetail->find('first', array(
2527            'fields' => array(
2528                'lesson_request_flg'
2529            ),
2530            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
2531            'recursive' => -1
2532        ));
2533        $this->UsersDetail->closeDBReplica();
2534
2535        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
2536        $this->set('lessonRequestFlg',$lessonRequestFlg);
2537
2538        //-- NJ-44869 skip communication modal
2539        $lessonSystemTroubleFlg = 0;
2540        $hideConnectionModalFlg = 0;
2541
2542        if (!empty($chatHash)) {
2543            $memcached = new myMemcached();
2544            $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
2545    
2546            if (!empty($lessonSystemTroubleCache)) {
2547                $memcached->delete('lesson_system_trouble_' . $chatHash);
2548                $lessonSystemTroubleFlg = 1;
2549            } 
2550        }
2551        
2552        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
2553        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
2554    }
2555
2556    /**
2557     * @api {post} /user/waiting/getStrengthRating getStrengthRating()
2558     * @apiName getStrengthRating
2559     * @apiGroup Waiting
2560     * @apiDescription Retrieves the strength rating items for a specific teacher in Native Camp. It returns the list of strength rating items.
2561     *
2562     * @apiBody {String} teacherId The ID of the teacher.
2563     * 
2564     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2565     * @apiSuccess {Object[]} strengthItems The list of strength rating items.
2566     *
2567     * @apiSuccessExample {json} Success-Response:
2568     *     {
2569     *         "res": true,
2570     *         "strengthItems": [
2571     *             {
2572     *                 "id": 1,
2573     *                 "name": "Friendly",
2574     *                 "rating": 5
2575     *             }
2576     *         ]
2577     *     }
2578     *
2579     * @apiError {Boolean} res Indicates whether the request was successful.
2580     *
2581     * @apiErrorExample {json} Error-Response:
2582     *     {
2583     *         "res": false
2584     *     }
2585     * 
2586     * @apiSampleRequest off
2587     */
2588    public function getStrengthRating() {
2589        $this->autoRender = false;
2590        $this->layout = false;
2591        $response = json_encode(array('res' => false)); // default
2592
2593        if($this->request->is('post')) {
2594            $post = $this->request->data;
2595            if (!isset($post['teacherId']) && $post['teacherId']) {
2596                return json_encode($response);
2597            }
2598            $teacherId = $post['teacherId'];
2599            
2600            $strengthItemsParams = array(
2601                'teacherId' => $teacherId,
2602                'type' => 0,
2603                'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir)
2604            );
2605
2606            $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
2607            
2608            if(!empty($strengthItems) && $strengthItems) {
2609                $response = json_encode(array(
2610                    'res' => true, 
2611                    'strengthItems' => $strengthItems, 
2612                ));
2613            }
2614        }
2615        return $response;
2616
2617    }
2618
2619    /**
2620     * @api {post} /user/waiting/getLessonHistory getLessonHistory()
2621     * @apiName getLessonHistory
2622     * @apiGroup Waiting
2623     * @apiDescription Retrieves the lesson history for a specific teacher and user in Native Camp. It returns the details of the lessons, including textbook information and chat logs.
2624     *
2625     * @apiBody {String} teacherId The ID of the teacher.
2626     * @apiBody {Boolean} [avatar_flg=false] Indicates if the request is for avatar lessons.
2627     * 
2628     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2629     * @apiSuccess {Object[]} lessonHistory The list of lesson history.
2630     * @apiSuccess {Number} lessonHistory.lesson_number The lesson number.
2631     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in JP format.
2632     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
2633     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson.
2634     * @apiSuccess {String} lessonHistory.textbook_url The URL of the textbook.
2635     * @apiSuccess {String} lessonHistory.categoryNameLabel The category name of the textbook.
2636     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The subcategory name of the textbook.
2637     * @apiSuccess {String} lessonHistory.textbookNameLabel The name of the textbook.
2638     * @apiSuccess {Number} lessonHistory.rate The rating of the lesson.
2639     * @apiSuccess {String} lessonHistory.chat_logs_url The URL of the chat logs.
2640     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates if the lesson has message logs.
2641     * @apiSuccess {String} lessonHistory.message_logs_url The URL of the message logs.
2642     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
2643     * @apiSuccess {String} lessonHistory.textbook_image The image URL of the textbook.
2644     *
2645     * @apiSuccessExample {json} Success-Response:
2646     *     {
2647     *         "res": true,
2648     *         "lessonHistory": [
2649     *             {
2650     *                 "lesson_number": 1,
2651     *                 "chatStartJPDate": "2023-12-01",
2652     *                 "chatStartTime": "10:00",
2653     *                 "lessonHistoryTime": "30分",
2654     *                 "textbook_url": "/textbook/page-detail/1/123",
2655     *                 "categoryNameLabel": "Category Name",
2656     *                 "subCategoryNameLabel": "Subcategory Name",
2657     *                 "textbookNameLabel": "Textbook Name",
2658     *                 "rate": 5,
2659     *                 "chat_logs_url": "/chat-history/123/abc123",
2660     *                 "has_message_logs": true,
2661     *                 "message_logs_url": "/lesson-message/detail/1",
2662     *                 "audio_count_log": 3,
2663     *                 "textbook_image": "http://example.com/image.jpg"
2664     *             }
2665     *         ]
2666     *     }
2667     *
2668     * @apiError {Boolean} res Indicates whether the request was successful.
2669     *
2670     * @apiErrorExample {json} Error-Response:
2671     *     {
2672     *         "res": false
2673     *     }
2674     * 
2675     * @apiSampleRequest off
2676     */
2677    public function getLessonHistory($sp = false, $teacherId = null) {
2678        $this->autoRender = false;
2679        $this->layout = false;
2680        $response = json_encode(array('res' => false)); // default
2681        
2682        if($this->request->is('post') || $sp) {
2683            $post = $this->request->data;
2684            if (!isset($post['teacherId']) && $post['teacherId']) {
2685                return json_encode($response);
2686            }
2687            $teacherId = $post['teacherId'] ?? $teacherId;
2688            $teacherId = Sanitize::escape($teacherId);
2689
2690            $isAvatarFlg = (isset($post['avatar_flg']) && $post['avatar_flg']) ? true : false;
2691
2692            //NC-7984 start
2693            if($isAvatarFlg){
2694                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10, "avatar");
2695            }else{
2696                $lesson_history_data = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, 10);
2697
2698            }
2699
2700            if(!empty($lesson_history_data) && $lesson_history_data) {
2701                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
2702
2703                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
2704                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
2705                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
2706
2707                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
2708
2709                    $lessonTime = $dteStart->diff($dteEnd);
2710                    $lessonHistoryTime = $lessonTime->format("%I");
2711
2712                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
2713
2714                    $categoryName = $value['TextbookCategory']['name'];
2715                    $subcategoryName = $value['TextbookSubategory']['name'];
2716                    $textbookName = $value['Textbook']['name'];
2717                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
2718
2719                    // - if has translated Category name
2720                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
2721                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
2722                    }
2723
2724                    // - if has translated subcategory name
2725                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
2726                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
2727                    }
2728
2729                    // - if has translated textbook name
2730                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
2731                        $textbookName = $value['GlobalTextbook']['gl_name'];
2732                    }
2733
2734                    // - set textbook name
2735                    $categoryNameLabel = $categoryName;
2736                    $subCategoryNameLabel = $subcategoryName;
2737                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
2738                    $textbookNameLabel = $textbookOrder . $textbookName;
2739                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
2740
2741                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
2742                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
2743                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
2744                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
2745
2746                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
2747                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
2748                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
2749                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
2750                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
2751                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
2752                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
2753                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
2754                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
2755                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
2756                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
2757                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
2758                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
2759                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
2760                }
2761                
2762                $response = json_encode(array(
2763                    'res' => true, 
2764                    'lessonHistory' => $lesson_history_data['lessonHistory']
2765                ));
2766
2767                if($sp) {
2768                    $response = $lesson_history_data['lessonHistory'];
2769                }
2770            }
2771            //NC-7984 end
2772        }
2773
2774        return $response;
2775
2776    }
2777
2778    /**
2779     * @api {post} /user/waiting/getPrimaryDetails getPrimaryDetails()
2780     * @apiName getPrimaryDetails
2781     * @apiGroup Waiting
2782     * @apiDescription Retrieves the primary details for a specific teacher in Native Camp. It returns the number of lessons, reservations, and comments for the teacher.
2783     *
2784     * @apiBody {String} teacherId The ID of the teacher.
2785     * 
2786     * @apiSuccess {Number} lessonCount The number of lessons for the teacher.
2787     * @apiSuccess {Number} reserveCount The number of reservations for the teacher.
2788     * @apiSuccess {Number} commentCount The number of comments for the teacher.
2789     *
2790     * @apiSuccessExample {json} Success-Response:
2791     *     {
2792     *         "lessonCount": 100,
2793     *         "reserveCount": 50,
2794     *         "commentCount": 20
2795     *     }
2796     *
2797     * @apiError {String} status The status of the request (NG).
2798     * @apiError {String} message The error message.
2799     *
2800     * @apiErrorExample {json} Error-Response:
2801     *     {
2802     *         "status": "NG",
2803     *         "message": "Invalid request."
2804     *     }
2805     * 
2806     * @apiSampleRequest off
2807     */
2808    public function getPrimaryDetails() {
2809        $this->autoRender = false;
2810        $this->layout = "";
2811        if (!$this->request->is('ajax')) { return ; }
2812        
2813        $teacherId = $this->request->data['teacherId'];
2814        $teacherId = Sanitize::escape($teacherId);
2815        
2816        if (empty($teacherId)) { return ; }
2817
2818        //number of lesson for all child accounts
2819        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
2820        //number of reservation for all child accounts
2821        $reserveCount = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId, 'avatar' => 1));
2822
2823        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
2824        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
2825        $options['language_id'] = $reviewLanguage[0];
2826        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
2827        $options['isAvatar'] = 1;
2828
2829        $userTable = new UserTable($this->Auth->user());
2830        $sapuriPlan = $userTable->isStudySapuri();
2831        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
2832        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
2833            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
2834        } else {
2835            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
2836        }
2837
2838        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
2839        $results = [
2840            'lessonCount' => $lessonCount,
2841            'reserveCount' => $reserveCount,
2842            'commentCount' => $commentCount,
2843        ];
2844
2845        echo json_encode($results);
2846        return;
2847    }
2848
2849    /**
2850     * @api {post} /user/waiting/getFavCount getFavCount()
2851     * @apiName getFavCount
2852     * @apiGroup Waiting
2853     * @apiDescription Retrieves the favorite count for a specific teacher in Native Camp. It returns the total number of favorites and whether the current user has favorited the teacher.
2854     *
2855     * @apiBody {String} teacherId The ID of the teacher.
2856     * 
2857     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2858     * @apiSuccess {Number} favCount The total number of favorites for the teacher.
2859     * @apiSuccess {Number} isFav Indicates whether the current user has favorited the teacher (1: Yes, 0: No).
2860     *
2861     * @apiSuccessExample {json} Success-Response:
2862     *     {
2863     *         "res": true,
2864     *         "favCount": 10,
2865     *         "isFav": 1
2866     *     }
2867     *
2868     * @apiError {Boolean} res Indicates whether the request was successful.
2869     *
2870     * @apiErrorExample {json} Error-Response:
2871     *     {
2872     *         "res": false
2873     *     }
2874     * 
2875     * @apiSampleRequest off
2876     */
2877    public function getFavCount() {
2878        $this->autoRender = false;
2879        $this->layout = false;
2880        $response = json_encode(array('res' => false)); // default
2881
2882        if($this->request->is('post')) {
2883            $post = $this->request->data;
2884            if (!isset($post['teacherId']) && $post['teacherId']) {
2885                return json_encode($response);
2886            }
2887            $teacherId = $post['teacherId'];
2888
2889            $favCount = $this->UsersFavorite->find('count', array(
2890                'conditions' => array(
2891                    'UsersFavorite.teacher_id'  => $teacherId
2892                )
2893            ));
2894
2895            $isFav = $this->UsersFavorite->find('count', array(
2896                'conditions' => array(
2897                    'UsersFavorite.user_id'     => $this->Auth->user('id'),
2898                    'UsersFavorite.teacher_id'     => $teacherId,
2899                )
2900            ));
2901
2902            if ($favCount){
2903                $response = json_encode(array('res' => true, 'favCount' => $favCount, 'isFav' => $isFav));
2904            }
2905        }
2906        return $response;
2907    }
2908
2909    /**
2910     * @api {post} /user/waiting/getAlbum getAlbum()
2911     * @apiName getAlbum
2912     * @apiGroup Waiting
2913     * @apiDescription Retrieves the album of images for a specific teacher in Native Camp. It returns the list of approved images for the teacher.
2914     *
2915     * @apiBody {String} teacherId The ID of the teacher.
2916     * 
2917     * @apiSuccess {Boolean} res Indicates whether the request was successful.
2918     * @apiSuccess {Object[]} [albums] The list of albums (only if the request was successful).
2919     * @apiSuccess {Number} albums.id The ID of the teacher image.
2920     * @apiSuccess {Number} albums.teacher_id The ID of the teacher.
2921     * @apiSuccess {Number} albums.approve_flg The approval flag of the image.
2922     * @apiSuccess {Number} albums.is_profile Indicates if the image is a profile image.
2923     * @apiSuccess {Number} albums.approve_required Indicates if the image requires approval.
2924     * @apiSuccess {String} albums.url The URL of the image.
2925     *
2926     * @apiSuccessExample {json} Success-Response:
2927     *     {
2928     *         "res": true,
2929     *         "albums": [
2930     *             {
2931     *                 "id": 1,
2932     *                 "teacher_id": 123,
2933     *                 "approve_flg": 1,
2934     *                 "is_profile": 0,
2935     *                 "approve_required": 0,
2936     *                 "url": "http://example.com/image.jpg"
2937     *             }
2938     *         ]
2939     *     }
2940     *
2941     * @apiError {Boolean} res Indicates whether the request was successful.
2942     *
2943     * @apiErrorExample {json} Error-Response:
2944     *     {
2945     *         "res": false
2946     *     }
2947     * 
2948     * @apiSampleRequest off
2949     */
2950    public function getAlbum() {
2951        $this->autoRender = false;
2952        $this->layout = false;
2953        $response = json_encode(array('res' => false)); // default
2954
2955        if($this->request->is('post')) {
2956            $post = $this->request->data;
2957            if (!isset($post['teacherId']) && $post['teacherId']) {
2958                return json_encode($response);
2959            }
2960            $teacherId = $post['teacherId'];
2961
2962            $this->TeacherImage->openDBReplica();
2963            $album = $this->TeacherImage->find('all', array(
2964                'fields' => array(
2965                    'TeacherImage.id',
2966                    'TeacherImage.teacher_id',
2967                    'TeacherImage.approve_flg',
2968                    'TeacherImage.is_profile',
2969                    'TeacherImage.approve_required',
2970                    'FileStorage.url'
2971                ),
2972                'conditions' => array(
2973                    'TeacherImage.teacher_id' => $teacherId,
2974                    'TeacherImage.is_profile' => 0,
2975                    'OR' => array(
2976                        'OR' => array(
2977                            'TeacherImage.approve_flg' => 1,
2978                            'TeacherImage.approve_required' => 0,
2979                        )
2980                    )
2981                ),
2982                'joins' => array(
2983                    array(
2984                        'type' => 'INNER',
2985                        'table' => 'file_storage',
2986                        'alias' => 'FileStorage',
2987                        'conditions' => array(
2988                            'TeacherImage.file_storage_id = FileStorage.id',
2989                            'FileStorage.uploader_type = 3',
2990                            'FileStorage.uploader_id' => $teacherId
2991                        )
2992                    )
2993                ),
2994                'order' => array('TeacherImage.id DESC')
2995            ));
2996            $this->TeacherImage->closeDBReplica();
2997
2998            if ($album){
2999                $response = json_encode(array('res' => true, 'albums' => $album));
3000            }
3001        }
3002        return $response;
3003    }
3004    
3005
3006    // NJ-3786 - arrange teacher data
3007    private function arrangeTeacherRecommendList( $params = array() ){
3008        $result = array();
3009        $data = isset( $params['data'] ) && $params['data'] ? $params['data'] : null;
3010        $userId = isset( $params['user_id'] ) && $params['user_id'] ? $params['user_id'] : null;
3011        $userData = isset($params['user_data']) && $params['user_data'] ?  $params['user_data'] : null;
3012        $nativeLanguage = isset($userData['native_language2']) && $userData['native_language2'] ?  $userData['native_language2'] : null;
3013        $platformArrangeApiList = (isset($params['platform_arrange']) && $params['platform_arrange'] == 'api') ;
3014        $categoryId = isset($params['category_id']) && $params['category_id'] ?  $params['category_id'] : null;
3015        $classStatusArr = Configure::read('teacher_lamp_color_class');
3016        $textbookImagUrl = null;
3017        if($categoryId){
3018            // Fetch textbook image
3019            $textbookParams = array(
3020                'conditions' => array('TextbookCategory.id' => $categoryId ),
3021                'fields' => array('TextbookCategory.image_big_url'),
3022                'recursive' => -1
3023            );
3024            ClassRegistry::init('TextbookCategory')->openDBReplica();
3025            $fetchTextbookData = ClassRegistry::init('TextbookCategory')->find('first',$textbookParams);
3026            ClassRegistry::init('TextbookCategory')->closeDBReplica();
3027            if($fetchTextbookData && isset($fetchTextbookData['TextbookCategory']['image_big_url']) && $fetchTextbookData['TextbookCategory']['image_big_url'] ){
3028                $textbookImagUrl = $fetchTextbookData['TextbookCategory']['image_big_url'];
3029            }
3030        }
3031
3032        if($data){
3033            foreach( $data as $index => $val ) {
3034                $teacherDetail = new TeacherTable($val['Teacher']);
3035                // - get countries
3036                $countries = strtolower($val['CountryCode']['country_name']);
3037                $explodeCountries = explode(' ', $countries);
3038                $implode = implode('_',$explodeCountries);
3039
3040                // - country name
3041                $countryName = $val['CountryCodeDetails']['country_name'] ? $val['CountryCodeDetails']['country_name'] : $val['CountryCode']['country_name'];
3042
3043                // - get residency
3044                $recidency = strtolower($countryName);
3045                $explodeRecidency = explode(' ', $recidency);
3046                $implodeResidency = implode('_',$explodeRecidency);
3047
3048                // - nationality
3049                $arrNationalityInfo = array(
3050                    "id" => "",
3051                    "name" => $val['CountryCode']['country_name'],
3052                    "flag" => $implode
3053                );
3054
3055                // - residence info
3056                $arrResidenceInfo = array(
3057                    "id" => "",
3058                    "name" => $countryName,
3059                    "flag" => $implodeResidency
3060                );
3061
3062                $getUserSettingLanguage = $nativeLanguage && $nativeLanguage == 'ja' ? $teacherDetail->jp_name : $teacherDetail->name ;
3063
3064                if( $platformArrangeApiList ) {
3065                    $result[$index] = array(
3066                        "id" => $teacherDetail->id,
3067                        "name" => $getUserSettingLanguage,
3068                        "name_ja" => $teacherDetail->jp_name,
3069                        "name_eng" => $teacherDetail->name,
3070                        "rating" => isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : 0,
3071                        "lessons" => isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0,
3072                        "favorite_count" => $this->UsersFavorite->getFavoriteCount($teacherDetail->id),
3073                        "age" => isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0,
3074                        "nationality_id" =>(int)$val['CountryCode']['id'],
3075                        "image_main" =>  $teacherDetail->getImageUrl(),
3076                        // - country, residence info
3077                        'residence_image' =>  FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png",
3078                        'residence_name' => __d('default',$arrResidenceInfo["name"]),
3079                        'country_name' => __d('default',$arrNationalityInfo["name"]),
3080                        'country_image' =>  FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png",
3081                        'textbook_image_url' =>  $textbookImagUrl
3082                    );
3083                } else {
3084                    $result[$index]['Teacher'] = $val['Teacher'];
3085                    $result[$index]['Teacher']['lesson_count'] = isset($val['TeacherTextbookStat']['lesson_count']) ? $val['TeacherTextbookStat']['lesson_count'] : 0;
3086                    $result[$index]['Teacher']['favorite_count'] = $this->UsersFavorite->getFavoriteCount($teacherDetail->id);
3087                    $result[$index]['Teacher']['age'] = isset($val[0]['Teacher__age']) ? (int)$val[0]['Teacher__age'] : 0;
3088                    $result[$index]['Teacher']['evaluation_average'] = isset($val['TeacherTextbookWeeklyRating']['ratings']) ? number_format((float)$val['TeacherTextbookWeeklyRating']['ratings'], 2, '.', '') : __d('waiting', '集計中');
3089                    $result[$index]['Teacher']['image_url'] = $teacherDetail->getImageUrl();
3090                    $result[$index]['Teacher']['residence_image'] = FULL_BASE_URL."/user/images/flag/".$arrResidenceInfo["flag"].".png";
3091                    $result[$index]['Teacher']['residence_name'] = __d('default',$arrResidenceInfo["name"]);
3092                    $result[$index]['Teacher']['country_name'] = __d('default',$arrNationalityInfo["name"]);
3093                    $result[$index]['Teacher']['country_image'] = FULL_BASE_URL."/user/images/flag/".$arrNationalityInfo["flag"].".png";
3094                    $result[$index]['Teacher']['textbook_image_url'] = $textbookImagUrl;
3095                }
3096            }
3097        }
3098
3099        return $result;
3100
3101    }
3102
3103    //not sued function
3104    public function checkReservation($teacher, $onair_status) {
3105
3106        // 定数 取得 (category=26)
3107        $getDefineMaster = $this->DefineMaster->getDefine('26');
3108        // 入室できる時間(n分前)
3109        $DefinePossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3110        // レッスンできる時間(n分前)
3111        $DefineLessonPossible = new DefineMasterTable($getDefineMaster[0]["DefineMaster"]);
3112        $reserver = 0;
3113
3114        $floored_seconds = floor(time() / (30 * 60)) * (30 * 60);
3115        $ceiled_seconds = ceil(time() / (30 * 60)) * (30 * 60);
3116        // 予約状況を取得
3117        $this->LessonSchedule->recursive = -1;
3118        $getLessonSchedule = $this->LessonSchedule->getLessonSchedule(date('Y-m-d H:i:s', $floored_seconds), date('Y-m-d H:i:s', $ceiled_seconds), $teacher->id, 'asc');
3119
3120        // 予約がある
3121        if(!empty($getLessonSchedule)) {
3122            $LessonSchedule = new LessonScheduleTable($getLessonSchedule[0]["LessonSchedule"]);
3123
3124            // 入室できる時間
3125            $possible_time = strtotime("- " . $DefinePossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3126
3127            // 予約時間
3128            $reservation_time = strtotime($LessonSchedule->lesson_time);
3129
3130            // レッスン可能な時間($lesson_possible_timeまで)
3131            $lesson_possible_time = strtotime("- " . $DefineLessonPossible->contents . " minutes", strtotime($LessonSchedule->lesson_time));
3132
3133            // 予約しているユーザのID
3134            $userID = $getLessonSchedule[0]['LessonSchedule']["user_id"];  //not used user id . undefined variable $getLessonSchedule
3135
3136            // 予約があっても 定数(category=26, sub_category=1)分前なら入室できる
3137            if(time() <= $possible_time && $onair_status == 1) {
3138                // 予約時間
3139                $this->set('ReservationTime', date('H:i', $reservation_time));
3140                // レッスン可能時間
3141                $this->set('PossibleTime',  date('H:i', $lesson_possible_time));
3142            }
3143
3144            # get minute now
3145            $minuteNow = (int) date("i");
3146
3147            // 予約してる人は自分
3148            if (
3149                $userID == $this->Auth->user('id') &&
3150                $onair_status == 2 &&
3151                !(
3152                    ($minuteNow >= 56 && $minuteNow <= 59) ||
3153                    ($minuteNow >= 26 && $minuteNow <= 29)
3154                )
3155            ) {
3156                $reserver = 1;
3157            }
3158        }
3159
3160        $this->set('isReserved', $reserver);
3161    }
3162
3163    /**
3164     * @api {get} /user/waiting/start/:teacher_id/:free_flg/:class_id/:chapter_id/:textbook_type start()
3165     * @apiName start
3166     * @apiGroup Waiting
3167     * @apiDescription Starts a lesson for a specific teacher and user in Native Camp. It checks various conditions and redirects to the appropriate page.
3168     *
3169     * @apiParam {String} teacher_id The ID of the teacher.
3170     * @apiParam {String} [free_flg=null] The free flag.
3171     * @apiParam {String} [class_id=1] The ID of the class.
3172     * @apiParam {String} [chapter_id=1] The ID of the chapter.
3173     * @apiParam {String} [textbook_type=null] The type of the textbook.
3174     * 
3175     * @apiSuccess {String} redirect_url The URL to which the user is redirected.
3176     *
3177     * @apiSuccessExample {json} Success-Response:
3178     *     {
3179     *         "redirect_url": "/class/index/123/1/1/1/1"
3180     *     }
3181     *
3182     * @apiError {String} status The status of the request (NG).
3183     * @apiError {String} message The error message.
3184     *
3185     * @apiErrorExample {json} Error-Response:
3186     *     {
3187     *         "status": "NG",
3188     *         "message": "Invalid request."
3189     *     }
3190     * 
3191     * @apiSampleRequest off
3192     */
3193    public function start($teacher_id, $free_flg=null, $class_id = null, $chapter_id = null, $textbook_type = null) {
3194        $this->autoRender = false;
3195        App::uses('myTools','Lib');
3196
3197        if (!$class_id)   $class_id     = 1;
3198        if (!$chapter_id) $chapter_id = 1;
3199
3200        if (is_null($teacher_id)) {
3201            return $this->redirect('/waiting/');
3202        }
3203        $data = $this->Teacher->findById($teacher_id);
3204        if (!$data) {
3205            return $this->redirect('/waiting/');
3206        }
3207
3208        /*
3209        * added in issue NC-488
3210        * check whether the user has been blocked already or not
3211        */
3212        //NJ-65055: params for checking teacher is hidden
3213        $isTeacherHiddenParams = array(
3214            'user_id' => $this->Auth->user('id'),
3215            'teacher_id' => $teacher_id
3216        );
3217
3218        if ((BlockListTable::isUserBlocked($this->Auth->User('id'), $teacher_id) == true) || $this->BlockList->isTeacherHide($isTeacherHiddenParams)) {
3219            return $this->redirect('/waiting/'); exit;
3220        }
3221
3222        // onairデータの中の講師IDがない
3223        $onAir = $this->LessonOnair->findByTeacherId($teacher_id);
3224        if (!isset($onAir['LessonOnair'])) {
3225            return $this->redirect('/');
3226        }
3227
3228        // レッスン中の場合
3229        if (!empty($onAir['LessonOnair']['status']) && $onAir['LessonOnair']['status']==3) {
3230            return $this->redirect('/waiting/detail/' . $teacher_id);
3231        }
3232
3233        // Overlapping reservation bug
3234        $lesson_available = $this->LessonSchedule->checkLessonAvailable($this->Auth->user('id'), $teacher_id);
3235        if (!$lesson_available) {
3236            return $this->redirect('/waiting/detail/' . $teacher_id);
3237        }
3238
3239
3240        $onAirId = $onAir['LessonOnair']['id'];
3241
3242        $this->Session->write('proceedFlag.clicked', 'true');
3243        return $this->redirect('/class/index/' . $teacher_id . '/' . $free_flg . '/' . $class_id . '/' . $chapter_id . '/' . $textbook_type);
3244    }
3245
3246    /**
3247     * @api {post} /user/waiting/teacherReserveList teacherReserveList()
3248     * @apiName teacherReserveList
3249     * @apiGroup Waiting
3250     * @apiDescription Retrieves the reservation list for a specific teacher in Native Camp. It returns various information about the available reservation slots, user eligibility, and more.
3251     *
3252     * @apiBody {String} teacherId The ID of the teacher.
3253     * @apiBody {Boolean} [counselingFlg=0] Indicates if the request is for counseling.
3254     * @apiBody {String} [hash16] The hash16 value for the user.
3255     * @apiBody {Number} [timeDiff=0] The time difference in seconds.
3256     * @apiBody {Boolean} [reservationHideFlg=false] Indicates if the reservation slots should be hidden.
3257     * @apiBody {Boolean} [hideLimitedPlanReservation=null] Indicates if the limited plan reservations should be hidden.
3258     * @apiBody {Number} [teacherCoin=0] The coin value for the teacher.
3259     * @apiBody {Number} [sapuriCoin=0] The coin value for Sapuri.
3260     * 
3261     * @apiSuccess {Object[]} days The list of days for the reservation slots.
3262     * @apiSuccess {String} days.Y The year.
3263     * @apiSuccess {String} days.m The month.
3264     * @apiSuccess {String} days.d The day.
3265     * @apiSuccess {String} days.w The day of the week.
3266     * @apiSuccess {String} days.reserve_range The reservation range for the day.
3267     * @apiSuccess {Boolean} days.canUseCoupon Indicates if a coupon can be used for the reservation.
3268     * @apiSuccess {Object[]} times The list of times for the reservation slots.
3269     * @apiSuccess {Object} reserved The reserved slots.
3270     * @apiSuccess {String} user_id The ID of the user.
3271     * @apiSuccess {Number} userCardCompany The card company of the user.
3272     * @apiSuccess {Number} timeDiff The time difference in seconds.
3273     * @apiSuccess {Object} reservedTz The reserved slots with timezone adjustments.
3274     * @apiSuccess {Boolean} limitedPlanAvailable Indicates if the limited plan reservation is available.
3275     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates if the limited plan reservations should be hidden.
3276     * @apiSuccess {Boolean} notCorporateLightTeachers Indicates if the teacher is not a corporate light teacher.
3277     * @apiSuccess {Boolean} corporateLightUser Indicates if the user is a corporate light user.
3278     * @apiSuccess {Boolean} corporateLimitedUser Indicates if the user is a corporate limited user.
3279     * @apiSuccess {Object} teacherInfo The information of the teacher.
3280     * @apiSuccess {Object} campaignPeriod The campaign period information.
3281     * @apiSuccess {Object} discountCampaignPeriod The discount campaign period information.
3282     * @apiSuccess {String} currentUserTime The current user time.
3283     * @apiSuccess {String} currentUtcOffset The current UTC offset.
3284     * @apiSuccess {Boolean} isShowCancellationAlert Indicates if the cancellation alert should be shown.
3285     * @apiSuccess {Object[]} otherReservations The list of other reservations.
3286     * @apiSuccess {Boolean} viewSlotForSapuri Indicates if the slot is for Sapuri.
3287     * @apiSuccess {String} studySapuriId The ID of the study Sapuri.
3288     * @apiSuccess {Object[]} lessonRequestSlot The list of lesson request slots.
3289     * @apiSuccess {Boolean} lessonRequestInvalidPlan Indicates if the lesson request plan is invalid.
3290     * @apiSuccess {String} teacherId The ID of the teacher.
3291     * @apiSuccess {Number} callanOption Indicates if the Callan option is available.
3292     * @apiSuccess {Object} user The user information.
3293     * @apiSuccess {Object} teacherData The teacher data.
3294     * @apiSuccess {String[]} weekday The list of weekdays.
3295     * @apiSuccess {Object} hiddenReservedTz The hidden reserved slots with timezone adjustments.
3296     * @apiSuccess {Boolean} canLive Indicates if the user can join live lessons.
3297     * @apiSuccess {Boolean} normalLitePlanCanReserveFlg Indicates if the normal lite plan can reserve.
3298     * @apiSuccess {Boolean} isNormalLitePlan Indicates if the user is on a normal lite plan.
3299     * @apiSuccess {Boolean} notNormalLitePlanTeacher Indicates if the teacher is not a normal lite plan teacher.
3300     * @apiSuccess {Boolean} teacherCoinDisableSlots Indicates if the teacher coin disables slots.
3301     * @apiSuccess {Boolean} excludeLessonRequestDiscount Indicates if the lesson request discount should be excluded.
3302     * @apiSuccess {Number} lessonRequestFlg The lesson request flag.
3303     * @apiSuccess {Boolean} notNewCampaignEligible Indicates if the user is not eligible for the new campaign.
3304     * @apiSuccess {String} teacherImageSrc The image URL of the teacher.
3305     * @apiSuccess {String} teacherName The name of the teacher.
3306     *
3307     * @apiSuccessExample {json} Success-Response:
3308     *     {
3309     *         "days": [
3310     *             {
3311     *                 "Y": "2023",
3312     *                 "m": "12",
3313     *                 "d": "01",
3314     *                 "w": "(金)",
3315     *                 "reserve_range": "10:00~11:00",
3316     *                 "canUseCoupon": true
3317     *             }
3318     *         ],
3319     *         "times": ["10:00", "10:30", "11:00"],
3320     *         "reserved": {...},
3321     *         "user_id": "123",
3322     *         "userCardCompany": 1,
3323     *         "timeDiff": 0,
3324     *         "reservedTz": {...},
3325     *         "limitedPlanAvailable": true,
3326     *         "hideLimitedPlanReservation": false,
3327     *         "notCorporateLightTeachers": false,
3328     *         "corporateLightUser": true,
3329     *         "corporateLimitedUser": false,
3330     *         "teacherInfo": {...},
3331     *         "campaignPeriod": {...},
3332     *         "discountCampaignPeriod": {...},
3333     *         "currentUserTime": "2023/12/01 10:00",
3334     *         "currentUtcOffset": "+09:00",
3335     *         "isShowCancellationAlert": true,
3336     *         "otherReservations": [...],
3337     *         "viewSlotForSapuri": true,
3338     *         "studySapuriId": "sapuri123",
3339     *         "lessonRequestSlot": [...],
3340     *         "lessonRequestInvalidPlan": false,
3341     *         "teacherId": "456",
3342     *         "callanOption": 1,
3343     *         "user": {...},
3344     *         "teacherData": {...},
3345     *         "weekday": ["(日)", "(月)", "(火)", "(水)", "(木)", "(金)", "(土)"],
3346     *         "hiddenReservedTz": {...},
3347     *         "canLive": true,
3348     *         "normalLitePlanCanReserveFlg": true,
3349     *         "isNormalLitePlan": true,
3350     *         "notNormalLitePlanTeacher": false,
3351     *         "teacherCoinDisableSlots": false,
3352     *         "excludeLessonRequestDiscount": false,
3353     *         "lessonRequestFlg": 1,
3354     *         "notNewCampaignEligible": false,
3355     *         "teacherImageSrc": "http://example.com/image.jpg",
3356     *         "teacherName": "John Doe"
3357     *     }
3358     *
3359     * @apiError {String} status The status of the request (NG).
3360     * @apiError {String} message The error message.
3361     *
3362     * @apiErrorExample {json} Error-Response:
3363     *     {
3364     *         "status": "NG",
3365     *         "message": "Invalid request."
3366     *     }
3367     * 
3368     * @apiSampleRequest off
3369     */
3370    public function teacherReserveList() {
3371        $this->layout = "";
3372
3373        if (!$this->request->is('post')) {
3374            return ;
3375        }
3376
3377        $data = $this->request->data;
3378        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : null;
3379        $counselingFlg = isset($data['counselingFlg']) ? $data['counselingFlg'] : 0;
3380        $hash16 = isset($data['hash16']) ? $data['hash16'] : null;
3381        $timeDiff = isset($data['timeDiff']) ? $data['timeDiff'] : 0;
3382        $reservationHideFlg = isset($data['reservationHideFlg']) ? $data['reservationHideFlg'] : false;
3383        $hideLimitedPlanReservation = isset($data['hideLimitedPlanReservation']) ? $data['hideLimitedPlanReservation'] : null;
3384        $teacherCoin = isset($data['teacherCoin']) ? $data['teacherCoin'] : 0;
3385        $sapuriCoin = isset($data['sapuriCoin']) ? $data['sapuriCoin'] : 0;
3386        $viewSlotForSapuri = false;
3387
3388        if (empty($teacherId)) {
3389            return ;
3390        }
3391
3392        $userId = $this->Auth->user('id');
3393        $teacher = ClassRegistry::init('Teacher')->getTeacherInfo($teacherId);
3394        $teacherInfo = $teacher['Teacher'];
3395        $userLanguage =  !empty($this->Auth->user('native_language2')) ? $this->Auth->user('native_language2') :Configure::read('default.user_language');
3396
3397        $this->User->recursive = -1;
3398        $user = $this->User->findById($userId);
3399
3400        // NJ-18780 : set var if callan half price teacher 
3401        $_isCallanHalfTeacher = (int) $teacherInfo['callan_halfprice_flg'];
3402
3403        if (
3404            $this->sharedUserData && 
3405            $this->isStudySapuriUser && 
3406            $sapuriCoin && 
3407            $teacherCoin <= $sapuriCoin
3408        ) {
3409            $viewSlotForSapuri = true;
3410            $userObj = new UserTable($this->sharedUserData['User']);
3411            $plan = $userObj->isStudySapuri();
3412            
3413            //NJ-10847 Hide Slots if Teacher has no Sapuri Textbook Badge
3414            $badgeParams = array('plan' => $plan, 'teacher_id' => $teacherId);
3415            $badges = TeacherBadgeTable::getSapuriStudentAndTeacherBadge($badgeParams);
3416            if (!$badges) {
3417                $viewSlotForSapuri = false;
3418            }
3419        }
3420
3421        // Hide reservations slot if lite plan and reservation coin is 0 
3422        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3423            $reservationHideFlg = true;
3424        }
3425
3426        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3427        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3428
3429        $times = array();
3430        $utcMin = explode(':', $this->utcOffset);
3431        if ($utcMin[1] == "45") {
3432            for ($i=0; $i<=23; $i++) {
3433                $times[] = sprintf("%02d",$i) . ':15';
3434                $times[] = sprintf("%02d",$i) . ':45';
3435            }
3436        } else {
3437            for ($i=0; $i<=23; $i++) {
3438                $times[] = sprintf("%02d",$i) . ':00';
3439                $times[] = sprintf("%02d",$i) . ':30';
3440            }
3441        }
3442
3443        $days = array();
3444
3445        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { // if the language is Custom language format
3446            $weekday = array( __dx('waiting', 'day_three_letter', '(日)'), __dx('waiting', 'day_three_letter','(月)'), __dx('waiting', 'day_three_letter','(火)'), __dx('waiting', 'day_three_letter','(水)'), __dx('waiting', 'day_three_letter','(木)'), __dx('waiting', 'day_three_letter','(金)'), __dx('waiting', 'day_three_letter','(土)') );
3447        } else { // if the language is not Custom language format
3448            $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
3449        }
3450
3451        $reserved = array();
3452        // if reservation_hide_flg, display open reservation slots
3453        
3454        // 予約状況を取得
3455        // ~ hide slots if teacher reservation hide flg is true
3456        if (!$reservationHideFlg) {
3457            $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3458                $userId,
3459                $teacherId,
3460                date('Ymd', time()),
3461                date('Ymd', strtotime("+8 days", time())),
3462                false,
3463                $reservationHideFlg
3464            );
3465        }
3466
3467        // // overide reserved for campaign hide slots for not eligeble users
3468        // if ($reservationCampaignHideFlg && isset($campaignDiscountFlg) && $campaignDiscountFlg) {
3469        //     $reserved = $this->LessonSchedule->findReserveListByTeacherIdAndLessondate(
3470        //         $userId,
3471        //         $teacherId,
3472        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['start_date'])),
3473        //         date('Ymd', strtotime($campaignDiscountFlg['CampaignInstructor']['end_date'])),
3474        //         false,
3475        //         $reservationCampaignHideFlg
3476        //     );
3477        // }
3478        
3479        // if have own reserved or available slot, check for live lesson slot
3480        $liveShift = array();
3481        $liveShiftLessonTimeData = [];
3482        if ($reserved) {
3483            $this->ShiftWorkOn->openDBReplica();
3484            $liveShift = $this->ShiftWorkOn->find('all', array(
3485                'fields' => ['ShiftWorkOn.lesson_time','DATE_FORMAT(ShiftWorkOn.lesson_time, \'%Y%m%d%H%i%S\') AS time'],
3486                'conditions' => array(
3487                    'ShiftWorkOn.teacher_id' => $teacherId,
3488                    'ShiftWorkOn.live_lesson_flg' => 1,
3489                    'ShiftWorkOn.hide_flg' => 0,
3490                    'ShiftWorkOn.lesson_time >= NOW()'
3491                ),
3492                'recursive' => -1
3493            ));
3494            $this->ShiftWorkOn->closeDBReplica();
3495
3496            $canLive = true;
3497            if ($liveShift) {
3498                if ($this->sharedUserData) {
3499                    $canLive = UserTable::canDoLiveViewing($this->sharedUserData['User']);
3500                }
3501                foreach ($liveShift as $shift) {
3502
3503                    if( isset($shift['ShiftWorkOn']['lesson_time']) && $shift['ShiftWorkOn']['lesson_time'] ) {
3504                        $liveShiftLessonTimeData[] = $shift['ShiftWorkOn']['lesson_time'];
3505                    }
3506
3507                    if ( empty($reserved[$shift[0]['time']]) ) {
3508                        continue;
3509                    }
3510
3511                    //-- open for live lesson resevation
3512                    if ( $reserved[$shift[0]['time']] == 9 ) {
3513                        if (!$canLive) {
3514                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3515                        } else {
3516                            $reserved[$shift[0]['time']] = 10;         //-- available live
3517                        }
3518
3519                    //-- own live lesson reservation
3520                    } elseif ( $reserved[$shift[0]['time']] == 2 ) {
3521                        $reserved[$shift[0]['time']] = 11;
3522
3523                    //-- other student live lesson reservation
3524                    } elseif ( $reserved[$shift[0]['time']] == 1 ) {
3525                        if (!$canLive) {
3526                            unset($reserved[$shift[0]['time']]);     //-- hide live lesson for invalid member
3527                        } else {
3528                            $reserved[$shift[0]['time']] = 12;         //-- reserved by another
3529                        }
3530                    }
3531                }
3532            }
3533        }
3534
3535        // Check if sapuri user and with in campaign's duration (sicth anniv, christmas)
3536        $ifSapuriAndCampaign = false;
3537        $sixthAnnivCampaignDateArr = Configure::read('campaign_config.sixth_anniv_1.period');
3538        // $christmasDateArr = Configure::read('campaign_config.christmas.period');
3539        // $goldenWeekDateArr = Configure::read('campaign_config.christmas.period');
3540        if (
3541            (
3542                (time() >= strtotime($sixthAnnivCampaignDateArr['start']) && time() <= strtotime($sixthAnnivCampaignDateArr['end']))
3543                // || (time() >= strtotime($christmasDateArr['start']) && time() <= strtotime($christmasDateArr['end']))
3544                // || (time() >= strtotime($goldenWeekDateArr['start']) && time() <= strtotime($goldenWeekDateArr['end']))
3545            )
3546            && $this->studySapuriId
3547        ) {
3548            $ifSapuriAndCampaign = true;
3549        }
3550        $isCorporateUser = isset($this->sharedUserData['User']) && !empty($this->sharedUserData['User']['corporate_id']);
3551        $forceFetchCampaignPeriod = $isCorporateUser || $this->isStudySapuriUser;
3552
3553        //campaign period start and end time
3554        $campaignPeriod = null;
3555        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3556            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
3557                'user_id' => $this->Auth->user('id'),
3558                'teacher_id' => $teacherId,
3559                'bypass_count' => $forceFetchCampaignPeriod
3560            ));
3561        }
3562
3563        if (($reserved && !$ifSapuriAndCampaign) || $forceFetchCampaignPeriod) {
3564            $discountcampaignPeriod = $this->CampaignInstructor->fetchNewCampaignPeriod(array(
3565                'user_id' => $this->Auth->user('id'),
3566                'teacher_id' => $teacherId,
3567                'bypass_count' => $forceFetchCampaignPeriod
3568            ));
3569        }
3570
3571        //NJ-28004 get current reservation
3572        $currentReseervations = $this->LessonSchedule->getCurrentTeacherReservation($teacherId, $userId);
3573
3574        //NC-3787 - get all users reservation except for current teacher
3575        $otherReservations = $this->LessonSchedule->getOtherReservationsExcept($teacherId, $userId);
3576        $reservedDate = '';
3577        $reservedTz = array();
3578        $teacherData = array();
3579        $reservedArr = is_array($reserved) ? $reserved : [];
3580
3581        $allLessonTimes = array_unique(array_merge(
3582            array_map(function($reservedData) {
3583                return date('Y-m-d H:i:s', strtotime($reservedData));
3584            }, array_keys($reservedArr)),
3585            $otherReservations,
3586            $currentReseervations
3587        ));
3588
3589        $allLessonTimes = is_array($allLessonTimes) ? $allLessonTimes : [];
3590        $lessonTimesParams = array(
3591            'lesson_times' => $allLessonTimes,
3592            'teacher_id' => $teacherId,
3593            'user_id' => $userId,
3594            'localize_dir' => $this->localizeDir,
3595            'campaign' => $discountcampaignPeriod
3596        );
3597
3598        $allReservationsData = $this->LessonSchedule->getAllReservationData($lessonTimesParams);
3599
3600        if (is_iterable($reserved)) {
3601            foreach($reserved as $key => $val) {
3602
3603                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3604                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($key));
3605                $campaignPeriod['lesson_time'] = $reservedLessonTime;
3606                $discountcampaignPeriod['lesson_time'] = $reservedLessonTime;
3607                $inCampaign = false;
3608                $inNewCampaign = false;
3609
3610                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3611                    $inNewCampaign = true;
3612                }
3613
3614                if ($this->CampaignInstructor->checkCampaignPeriod($discountcampaignPeriod)) {
3615                    $inNewCampaign = true;
3616                }
3617
3618                if( $liveShiftLessonTimeData && in_array($reservedLessonTime,$liveShiftLessonTimeData) ) {
3619                    $teacherSlotEvent = Configure::read('reservation_event_type.live_lesson');
3620                } elseif( $inCampaign ) {
3621                    $teacherSlotEvent = Configure::read('reservation_event_type.popular_campaign');
3622                }elseif( $inNewCampaign ) {
3623                    $teacherSlotEvent = Configure::read('reservation_event_type.discount_campaign');
3624                }
3625
3626                $teacherData = in_array($reservedLessonTime, $otherReservations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3627                $currentTeacherData = in_array($reservedLessonTime, $currentReseervations) ? ($allReservationsData[$reservedLessonTime] ?? []) : [];
3628
3629                $reservedDatas = [
3630                    'reserved' => $key,
3631                    'val' => $val,
3632                    'reservation_event' => $teacherSlotEvent,
3633                    'teacherData' => $teacherData,
3634                    'currentTeacherData' => $currentTeacherData
3635                ];
3636
3637                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3638                $reservedTz[$timeKeySlot] = $reservedDatas;
3639
3640                $currentDate = substr($key, 0,8);
3641                $min = date('i', strtotime($key));
3642                $hour = intval(date('H', strtotime($key)));
3643                if ($min == '30') {
3644                    $hour = $hour + 1;
3645                    $min = ":00";
3646                } else {
3647                    $min = ":30";
3648                }
3649                if ($reservedDate != $currentDate) {
3650                    if (!isset($reservedRange[$currentDate][0])) {
3651                        $reservedRange[$currentDate][0] = date('H:i', strtotime($key));
3652                        $reservedRange[$currentDate][1] = strval($hour).$min;
3653                    } else {
3654                        $reservedRange[$currentDate][1] = strval($hour).$min;
3655                    }
3656                } else {
3657                    $reservedRange[$currentDate][1] = strval($hour).$min;
3658                }
3659                $rKeys = array_keys($reservedRange);
3660                $rLastKey = end($rKeys);
3661                $reservedDate = $rLastKey;
3662
3663            }
3664        }
3665
3666        if (is_iterable($otherReservations)) {
3667            foreach($otherReservations as $key => $val) {
3668                $teacherSlotEvent = Configure::read('reservation_event_type.normal');
3669                $timeKeySlot = TimezoneTable::computeTimeToUser(array('time' => strtotime($val), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'));
3670                $reservedLessonTime = date('Y-m-d H:i:s', strtotime($val));
3671
3672                // - do nothing - avoid conflict
3673                if (isset($reservedTz[$timeKeySlot])) {
3674                    continue;
3675                }
3676
3677                // - set reservation info
3678                $teacherData = $allReservationsData[$reservedLessonTime] ?? [];
3679                $currentTeacherData = $allReservationsData[$reservedLessonTime] ?? [];
3680
3681                // - set reservation data
3682                $reservedDatas = [
3683                    'reserved' => $val,
3684                    'val' => [],
3685                    'reservation_event' => $teacherSlotEvent,
3686                    'teacherData' => $teacherData,
3687                    'currentTeacherData' => $currentTeacherData
3688                ];
3689
3690                // - set reserved TZ
3691                $reservedTz[$timeKeySlot] = $reservedDatas;
3692            }
3693        }
3694
3695        $coupon = false;
3696        $couponDateCanUse = date('Y-m-d');
3697        $ccPeriod = false;
3698        if (!is_null($hash16)) {
3699            $freeTicket = false;
3700            if(PaymentTable::checkIfPaidUser($userId, $hash16)) {
3701                $freeTicket = true;
3702            } elseif (PaymentTable::checkIfCardAuth($userId, $hash16)) {
3703                $freeTicket = true;
3704            }
3705
3706            if ($freeTicket) {
3707                // check if can use coupon for reservation
3708                $coupon = ClassRegistry::init('UserCoupon')->canUseCoupon($userId);
3709                // get last coupon date used
3710                $couponDateCanUse = ClassRegistry::init('UserCoupon')->getDateCouponCanUse($userId);
3711
3712                // check if coupon campaign period
3713                $ccPeriod = myTools::couponCampaignPeriod();
3714            }
3715        }
3716        for ($i=0; $i<=7; $i++) {
3717            $cTime = strtotime("+" . $i . " days", $this->displayTime);
3718            $canUseCoupon = false;
3719            if (
3720                $couponDateCanUse && $coupon && $ccPeriod && !$counselingFlg
3721                && strtotime(date('Y-m-d', $cTime)) >= strtotime($couponDateCanUse)
3722            ) {
3723                $canUseCoupon = true;
3724            }
3725            $resRange = (isset($reservedRange[date('Ymd', $cTime)]))?$reservedRange[date('Ymd', $cTime)][0].'~'.$reservedRange[date('Ymd', $cTime)][1]:'';
3726            $days[] = array(
3727                'Y' => date('Y', $cTime),
3728                'm' => date('m', $cTime),
3729                'd' => date('d', $cTime),
3730                'w' => $weekday[date("w", $cTime)],
3731                'reserve_range' => $resRange,
3732                'canUseCoupon' => $canUseCoupon
3733            );
3734        }
3735
3736        // NC-4546 - check phone verification auth
3737        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
3738            'conditions' => array(
3739                'user_id' => $this->Auth->User('id'),
3740                'status' => 0
3741            )
3742        ));
3743        $notCorporateLightTeachers = false;
3744        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id'] );
3745
3746        if ( isset($corporateType) && $corporateType == Configure::read("corporate_type.light") ) {
3747            $checkCorpLightTeacher = ClassRegistry::init('Teacher')->corporateLightTeacher($teacherId);
3748            if (!$checkCorpLightTeacher) {
3749                $notCorporateLightTeachers = true;
3750            }
3751        }
3752
3753
3754        $grc = $this->getReserveAndCancelled($teacherId);
3755        $isShowCancellationAlert = $grc['this_month_cancellation_rate'] >= Configure::read('alert_cancellation_rate') ? true : false;
3756
3757        $limitedPlanAvailable = false;
3758
3759        // if user is corporate limited check if limited plan reservation is ON
3760        if ($corporateType == Configure::read("corporate_type.limited")) {
3761            $this->TeacherRankCoin->openDBReplica();
3762            $teacherRankCoin = $this->TeacherRankCoin->find('first', array(
3763                'fields' => array('TeacherRankCoin.limited_plan_reservation'),
3764               'conditions' => array('TeacherRankCoin.id' => $teacher['Teacher']['rank_coin_id'])
3765            ));
3766            $this->TeacherRankCoin->closeDBReplica();
3767
3768            $teacherRankCoin = $teacherRankCoin ? $teacherRankCoin['TeacherRankCoin'] : false;
3769            $limitedPlanAvailable = $teacherRankCoin && $teacherRankCoin['limited_plan_reservation'];
3770        }
3771        
3772        $callan_unlimited_flg = 0;
3773
3774
3775        # NJ-19429: check if teacher is in campaign
3776        if(
3777            (isset($user['User']['callan_option']) && $user['User']['callan_option'])
3778            ||
3779            (isset($user['User']['native_option']) && $user['User']['native_option'])
3780        ) {
3781            // - check existing reservation
3782            $has_callan_option_reserved = $this->LessonSchedule->hasCallanOptionReserved($userId);
3783            
3784            if($has_callan_option_reserved == 0) {
3785                // - check teacher callan option
3786                $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherInfo['current_rank_id']);
3787                $callan_unlimited_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? 1 : 0;
3788            }
3789        }
3790        
3791        #NJ-18780:set to allow normal lite plan to reserve
3792        $normalLitePlanCanReserveFlg = true;
3793        $isNormalLitePlan = false;
3794        $notNormalLitePlanTeacher = false;
3795
3796        $lessonRequestSlot = array();
3797
3798        if($this->isStudySapuriTosUser) {
3799            $lessonRequestSlot = array();            
3800        } else if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && $teacherCoin <= 0) {
3801            $lessonRequestSlot = array();
3802        } else {
3803            //-- lesson request schedule
3804
3805            // - NJ-46366: prefetch lesson request slot
3806            $prefetchStart = date("Y-m-d 00:00:00");
3807            $prefetchEnd = date("Y-m-d 23:59:59", strtotime("+7 day"));
3808
3809            $prefetchedUserReservationData = $this->LessonSchedule->getReservationData(
3810                ['startDate' => $prefetchStart, 
3811                'endDate' => $prefetchEnd], 
3812                $user['User']['id'],
3813                $userLanguage
3814            );
3815    
3816            $prefetchedUsersCancelledReservationData = $this->LessonScheduleCancel->hasSlotBeenCancelled([
3817                'user_id' => $user['User']['id'],
3818                'lesson_time' => [
3819                    'startDate' => $prefetchStart, 
3820                    'endDate' => $prefetchEnd
3821                ]
3822            ]);
3823            
3824            $lessonRequestSlot = $this->LessonSchedule->lessonRequestSlotDetail(array(
3825                'user_id' => $userId,
3826                'teacher_id' => $teacherId,
3827                'timeDiffSecond' => $this->timeDiffSecond,
3828                'user_language' => $this->localizeDir,
3829                'campaign' => $discountcampaignPeriod,
3830                'userReservationData' => $prefetchedUserReservationData,
3831                'cancelledReservationData' => $prefetchedUsersCancelledReservationData
3832            ));
3833
3834            //-override hide dates or closed slots fetch reservation data
3835            $hiddenReservedTz = [];
3836            $resData = $this->LessonSchedule->getHiddenReservation([
3837                'user_id' => $userId
3838            ]);
3839
3840            if ($resData) {
3841                foreach ($resData as $key => $row) {
3842                    $lessonReqquestSlotData = $this->LessonSchedule->getReservationData($key, $userId, $this->localizeDir);
3843                    if (!empty($lessonReqquestSlotData)) {
3844                        $lessonReqquestSlotData['icon_color'] = $this->LessonSchedule->getIconColor($lessonReqquestSlotData, $key);
3845                        $hiddenReservedTz[TimezoneTable::computeTimeToUser(array('time' => strtotime($key), 'timestamp' => $this->timeDiffSecond, 'format' => 'YmdHis'))] = $lessonReqquestSlotData;
3846                    }
3847                }
3848            }
3849        }
3850
3851        $membershipStatusIndex = UserTable::getStudentMembershipStatus($this->Auth->User('id'));
3852        $CampaignEligible = $this->CampaignInstructor->verifyStudentMembership($this->Auth->User('id'));
3853        $isNotNewCampaignEligible = !$CampaignEligible['verified'];
3854
3855        // NJ-33414
3856        $this->UsersDetail->openDBReplica();
3857        $fetchUsersDetail = $this->UsersDetail->find('first', array(
3858            'fields' => array(
3859                'user_id',
3860                'lesson_request_flg'
3861            ),
3862            'conditions' =>  array('user_id' => $userId),
3863            'recursive' => -1
3864        ));
3865        $this->UsersDetail->closeDBReplica();
3866        // - check if light plan and over ride to allow reserve on live lesson
3867        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans'))) {
3868            # not allow user to reserve live lesson
3869            $canLive = false;
3870        
3871            #set to normal lite plan user
3872            $isNormalLitePlan = true;
3873        
3874            #count the total upcoming reservation limited only to 1 reservation ?
3875            $liteUserReservationCount = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
3876        
3877            if ($liteUserReservationCount >= Configure::read("lite_plan_maximum_number_of_total_reservation")) {
3878                # not allow to reserve any more
3879                $normalLitePlanCanReserveFlg = false;
3880            }
3881
3882            // - check if teacher is callan half price
3883            if ($_isCallanHalfTeacher == 1 && empty($campaign)) {
3884                $notNormalLitePlanTeacher = true;
3885
3886                // - hide slots for lesson request 
3887                $lessonRequestSlot =  array();
3888            }
3889        }
3890
3891        //NJ-19429: teacher coin in slot restriction
3892        $teacherCoinDisableSlots = false;
3893        if($teacherCoin > 100){
3894            $isSlotReserveDisabled = in_array($membershipStatusIndex, Configure::read('slots_disabled_membership'));
3895            if($isSlotReserveDisabled){
3896                $lessonRequestSlot = array();
3897                $teacherCoinDisableSlots = true;
3898            }
3899        }
3900
3901        // NJ-47838 : check if live lesson callan discount campaign is enabled 
3902        $isLiveDiscountCallanCampaignCount = ClassRegistry::init('CampaignTagControl')->checkTeacherLiveCallanTag($discountcampaignPeriod['campaign_tag_id']);
3903        $excludeLessonRequestDiscount ??= '';
3904        $this->set(array(
3905            'smsThroughFlg' => isset($user['User']['sms_through_flg']) ? $user['User']['sms_through_flg'] : false,
3906            'verifyCount' => $verifyCount,
3907            'days' => $days,
3908            'times' => $times,
3909            'reserved' => $reserved,
3910            'user_id' => ($this->Auth->loggedIn()) ? $userId : null,
3911            'userCardCompany' => isset($user['User']['card_company']) ? $user['User']['card_company'] : 0,
3912            'timeDiff' => $timeDiff,
3913            'reservedTz' => $reservedTz,
3914            'limitedPlanAvailable' => $limitedPlanAvailable,
3915            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
3916            'notCorporateLightTeachers' => $notCorporateLightTeachers,
3917            'corporateLightUser' => ($corporateType == Configure::read("corporate_type.light")),
3918            'corporateLimitedUser' => ($corporateType == Configure::read("corporate_type.limited")),
3919            'teacherInfo' => $teacherInfo,
3920            'campaignPeriod' => $campaignPeriod,
3921            'discountCampaignPeriod' => $discountcampaignPeriod,
3922            'currentUserTime' => date(
3923                isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support")) ? 
3924                'd/m/Y G:i' : 'Y/m/d G:i', 
3925                $this->displayTime
3926            ),
3927            'currentUtcOffset' => $this->utcOffset,
3928            'isShowCancellationAlert' => $isShowCancellationAlert,
3929            'otherReservations' => $otherReservations,
3930            'viewSlotForSapuri' => $viewSlotForSapuri,
3931            'studySapuriId' => $this->studySapuriId,
3932            'lessonRequestSlot' => $lessonRequestSlot,
3933            'lessonRequestInvalidPlan' => in_array($membershipStatusIndex, [12, 13]),
3934            'teacherId' => $teacherId,
3935            'callanOption' => $callan_unlimited_flg,
3936            'user' => $user,
3937            'teacherData' => $teacherInfo,
3938            'weekday' => $weekday,
3939            'hiddenReservedTz' => $hiddenReservedTz,
3940            'canLive' => $canLive,
3941            'normalLitePlanCanReserveFlg' => $normalLitePlanCanReserveFlg,
3942            'isNormalLitePlan' => $isNormalLitePlan,
3943            'notNormalLitePlanTeacher' => $notNormalLitePlanTeacher,
3944            'teacherCoinDisableSlots' => $teacherCoinDisableSlots,
3945            'excludeLessonRequestDiscount'=> $excludeLessonRequestDiscount ? true : false,
3946            'lessonRequestFlg' => $fetchUsersDetail ? (int)$fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1,   // NJ-33414
3947            'notNewCampaignEligible' => $isNotNewCampaignEligible,
3948            'isLiveDiscountCallanCampaignCount' => $isLiveDiscountCallanCampaignCount
3949        ));
3950
3951        // get teacher information
3952        $teacher = new TeacherTable($teacherInfo);
3953        $teacherImageSrc = $teacher->getImageUrl();
3954        $teacherName = $teacher->getName();
3955        $this->set('teacherImageSrc', $teacherImageSrc);
3956        $this->set('teacherName', $teacherName);
3957
3958        $this->render('teacher_reserve_list_new');
3959
3960    }
3961
3962    //not used function
3963    public function updateChapterOptions() {
3964        $this->autoRender = false;
3965        $classId = $this->request->data['classid'];
3966        $teacherId = $this->request->data['teacherid'];
3967
3968        if (isset($this->request->data['firstid'])) {
3969            $firstId = $this->request->data['firstid'];
3970        } else {
3971            $firstId = '';
3972        }
3973
3974        if (isset($this->request->data['lastid'])) {
3975            $lastId = $this->request->data['lastid'];
3976        } else {
3977            $lastId = '';
3978        }
3979        return $this->result($teacherId, $classId, $firstId, $lastId);
3980    }
3981
3982    /**
3983     * @api {post} /user/waiting/result/:teacherId/:classId/:firstId/:lastId result()
3984     * @apiName result
3985     * @apiGroup Waiting
3986     * @apiDescription Retrieves the list of chapters for a specific class and teacher in Native Camp. It returns the updated list of chapters along with the first and last chapter IDs.
3987     *
3988     * @apiParam {String} teacherId The ID of the teacher.
3989     * @apiParam {String} classId The ID of the class.
3990     * @apiParam {String} [firstId] The ID of the first chapter.
3991     * @apiParam {String} [lastId] The ID of the last chapter.
3992     * 
3993     * @apiSuccess {Object[]} chapterList The list of chapters.
3994     * @apiSuccess {String} chapterList.UsersLastViewedTextbook.last_viewed_date The last viewed date of the chapter.
3995     * @apiSuccess {String} chapterList.LessonText.chapter_id The ID of the chapter.
3996     * @apiSuccess {String} chapterList.LessonText.chapter The name of the chapter.
3997     * @apiSuccess {String} firstChapter The ID of the first chapter.
3998     * @apiSuccess {String} lastChapter The ID of the last chapter.
3999     * @apiSuccess {String} teacherId The ID of the teacher.
4000     * @apiSuccess {String} classId The ID of the class.
4001     * @apiSuccess {Object} lastViewedTextInfo The information of the last viewed text.
4002     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.last_viewed_date The last viewed date of the text.
4003     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.class_id The ID of the class.
4004     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.chapter_id The ID of the chapter.
4005     * @apiSuccess {String} lastViewedTextInfo.UsersLastViewedTextbook.preset Indicates if the text is preset.
4006     * @apiSuccess {String} userId The ID of the user.
4007     *
4008     * @apiSuccessExample {json} Success-Response:
4009     *     {
4010     *         "chapterList": [
4011     *             {
4012     *                 "UsersLastViewedTextbook": {
4013     *                     "last_viewed_date": "2023-12-01 10:00:00"
4014     *                 },
4015     *                 "LessonText": {
4016     *                     "chapter_id": "1",
4017     *                     "chapter": "Chapter 1"
4018     *                 }
4019     *             }
4020     *         ],
4021     *         "firstChapter": "1",
4022     *         "lastChapter": "10",
4023     *         "teacherId": "123",
4024     *         "classId": "456",
4025     *         "lastViewedTextInfo": {
4026     *             "UsersLastViewedTextbook": {
4027     *                 "last_viewed_date": "2023-12-01 10:00:00",
4028     *                 "class_id": "456",
4029     *                 "chapter_id": "1",
4030     *                 "preset": "0"
4031     *             }
4032     *         },
4033     *         "userId": "789"
4034     *     }
4035     *
4036     * @apiError {String} status The status of the request (NG).
4037     * @apiError {String} message The error message.
4038     *
4039     * @apiErrorExample {json} Error-Response:
4040     *     {
4041     *         "status": "NG",
4042     *         "message": "Invalid request."
4043     *     }
4044     * 
4045     * @apiSampleRequest off
4046     */
4047    public function result($teacherId, $classId, $firstId, $lastId) {
4048        $user_id = $this->Auth->user('id');
4049        if ($lastId != '') {
4050            $lastId = $this->request->data['lastid'];
4051            $classChapterList = $this->LessonText->find('all',
4052                array(
4053                    'joins' => array(
4054                        array(
4055                            'type'  => 'LEFT',
4056                            'table' => 'users_last_viewed_textbooks',
4057                            'alias' => 'UsersLastViewedTextbook',
4058                            'conditions' => array(
4059                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4060                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4061                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4062                                'UsersLastViewedTextbook.preset !=' => 1
4063                            )
4064                        )
4065                    ),
4066                    'fields' => array(
4067                        'UsersLastViewedTextbook.last_viewed_date',
4068                        'LessonText.chapter_id',
4069                        'LessonText.chapter'
4070                    ),
4071                    'conditions' => array(
4072                        'LessonText.class_id' => $classId,
4073                        'LessonText.chapter_id >' => $lastId,
4074                        'LessonText.status' => 1
4075                    ),
4076                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4077                )
4078            );
4079
4080        } else if ($firstId != '') {
4081            $firstId = $this->request->data['firstid'];
4082            $classChapterList = $this->LessonText->find('all',
4083                array(
4084                    'joins' => array(
4085                        array(
4086                            'type'  => 'LEFT',
4087                            'table' => 'users_last_viewed_textbooks',
4088                            'alias' => 'UsersLastViewedTextbook',
4089                            'conditions' => array(
4090                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4091                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4092                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4093                                'UsersLastViewedTextbook.preset !=' => 1
4094                            )
4095                        )
4096                    ),
4097                    'fields' => array(
4098                        'UsersLastViewedTextbook.last_viewed_date',
4099                        'LessonText.chapter_id',
4100                        'LessonText.chapter'
4101                    ),
4102                    'conditions' => array(
4103                        'LessonText.class_id' => $classId,
4104                        'LessonText.chapter_id <' => $firstId,
4105                        'LessonText.status' => 1
4106                    ),
4107                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4108                )
4109            );
4110        } else {
4111
4112            $classChapterList = $this->LessonText->find('all',
4113                array(
4114                    'joins' => array(
4115                        array(
4116                            'type'  => 'LEFT',
4117                            'table' => 'users_last_viewed_textbooks',
4118                            'alias' => 'UsersLastViewedTextbook',
4119                            'conditions' => array(
4120                                'UsersLastViewedTextbook.user_id    = ' . $user_id,
4121                                'UsersLastViewedTextbook.class_id   = LessonText.class_id',
4122                                'UsersLastViewedTextbook.chapter_id = LessonText.chapter_id',
4123                                'UsersLastViewedTextbook.preset !=' => 1
4124                            )
4125                        )
4126                    ),
4127                    'fields' => array(
4128                        'UsersLastViewedTextbook.last_viewed_date',
4129                        'LessonText.class_id',
4130                        'LessonText.chapter_id',
4131                        'LessonText.chapter'
4132                    ),
4133                    'conditions' => array(
4134                        'LessonText.class_id' => $classId,
4135                        'LessonText.status' => 1
4136                    ),
4137                    'order' => 'ISNULL(LessonText.orderno), LessonText.orderno ASC, LessonText.chapter_id ASC'
4138                )
4139            );
4140        }
4141
4142        $classChapterFirstLast = $this->LessonText->find('first',
4143            array(
4144                'conditions' => array(
4145                    'LessonText.class_id' => $classId
4146                ),
4147                'fields' => array(
4148                    'MIN(LessonText.chapter_id) as first_chapter',
4149                    'MAX(LessonText.chapter_id) as last_chapter'
4150                )
4151            )
4152        );
4153
4154        if ($classChapterFirstLast) {
4155            $this->set('firstChapter', $classChapterFirstLast[0]['first_chapter']);
4156            $this->set('lastChapter', $classChapterFirstLast[0]['last_chapter']);
4157        } else {
4158            $this->set('firstChapter', '');
4159            $this->set('lastChapter', '');
4160        }
4161
4162        $this->set('teacherId', $teacherId);
4163        $this->set('classId', $classId);
4164        if ($firstId != '') {
4165            $classChapterList = array_reverse($classChapterList);
4166        }
4167
4168        //NC-634
4169        $lastViewedText = $this->UsersLastViewedTextbook->find(
4170            'all',
4171            array(
4172                'conditions' => array(
4173                    'UsersLastViewedTextbook.user_id' => $user_id,
4174                    'UsersLastViewedTextbook.preset !=' => 1
4175                ),
4176                'order' => array('UsersLastViewedTextbook.modified DESC'),
4177                'limit' => 1
4178            )
4179        );
4180
4181        $lastViewedTextInfo = array();
4182        if(isset($lastViewedText[0]) && isset($lastViewedText[0]['UsersLastViewedTextbook'])) {
4183            $lastViewedTextInfo = $lastViewedText[0];
4184        }
4185
4186        $this->set('lastViewedTextInfo', $lastViewedTextInfo);
4187        $this->set('chapterList', $classChapterList);
4188        $this->set('userId', $this->Auth->user('id'));
4189        $this->render('result', 'ajax');
4190    }
4191
4192    /**
4193     * @api {post} /user/waiting/loadMoreComments loadMoreComments()
4194     * @apiName loadMoreComments
4195     * @apiGroup Waiting
4196     * @apiDescription Loads more comments for a specific teacher or counselor in Native Camp. It returns the list of comments and indicates if there are more pages available.
4197     *
4198     * @apiBody {Number} page The page number to load.
4199     * @apiBody {String} teacherId The ID of the teacher.
4200     * @apiBody {Boolean} [isCounseling=false] Indicates if the request is for counseling comments.
4201     * @apiBody {Boolean} [isAvatar=false] Indicates if the request is for avatar comments.
4202     * @apiBody {Number} [order=0] The order of the comments.
4203     * 
4204     * @apiSuccess {Object[]} results The list of comments.
4205     * @apiSuccess {Number} results.id The ID of the comment.
4206     * @apiSuccess {String} results.star The HTML content for the star rating.
4207     * @apiSuccess {Number} results.age The age of the user who made the comment.
4208     * @apiSuccess {String} results.gender The gender of the user who made the comment.
4209     * @apiSuccess {String} results.user_comment The comment text.
4210     * @apiSuccess {String} results.date The date of the comment.
4211     * @apiSuccess {Object} results.textbook The textbook information.
4212     * @apiSuccess {String} results.textbook.textUrl The URL of the textbook.
4213     * @apiSuccess {String} results.textbook.textbook_image The image URL of the textbook.
4214     * @apiSuccess {String} results.textbook.textbook_name_lv1 The level 1 name of the textbook.
4215     * @apiSuccess {String} results.textbook.textbook_name_lv2 The level 2 name of the textbook.
4216     * @apiSuccess {String} results.textbook.textbook_name_lv3 The level 3 name of the textbook.
4217     * @apiSuccess {Number} results.review_id The ID of the review.
4218     * @apiSuccess {Number} results.like_total The total number of likes for the comment.
4219     * @apiSuccess {Number} results.dislike_total The total number of dislikes for the comment.
4220     * @apiSuccess {Number} results.voted Indicates if the user has voted on the comment (0: No, 1: Yes).
4221     * @apiSuccess {Boolean} lastPage Indicates if there are no more pages of comments available.
4222     *
4223     * @apiSuccessExample {json} Success-Response:
4224     *     {
4225     *         "results": [
4226     *             {
4227     *                 "id": 1,
4228     *                 "star": "<div>Star Rating</div>",
4229     *                 "age": 25,
4230     *                 "gender": "Male",
4231     *                 "user_comment": "Great lesson!",
4232     *                 "date": "2023-12-01",
4233     *                 "textbook": {
4234     *                     "textUrl": "http://example.com/textbook",
4235     *                     "textbook_image": "http://example.com/image.jpg",
4236     *                     "textbook_name_lv1": "Level 1",
4237     *                     "textbook_name_lv2": "Level 2",
4238     *                     "textbook_name_lv3": "Level 3"
4239     *                 },
4240     *                 "review_id": 1,
4241     *                 "like_total": 10,
4242     *                 "dislike_total": 2,
4243     *                 "voted": 1
4244     *             }
4245     *         ],
4246     *         "lastPage": false
4247     *     }
4248     *
4249     * @apiError {String} status The status of the request (NG).
4250     * @apiError {String} message The error message.
4251     *
4252     * @apiErrorExample {json} Error-Response:
4253     *     {
4254     *         "status": "NG",
4255     *         "message": "Invalid request."
4256     *     }
4257     * 
4258     * @apiSampleRequest off
4259     */
4260    public function loadMoreComments() {
4261            $this->autoRender = false;
4262            $this->layout = false;
4263            $userId = $this->Auth->user('id');
4264            if ($this->request->is('ajax')) {
4265                $perPage = 4;
4266                $data = $this->request->data;
4267
4268                // - if ajax is from counseling
4269                if (isset($data['isCounseling']) && $data['isCounseling']) {
4270                    $data['teacherId'] = $this->Teacher->getCounselorId();
4271                }
4272
4273                $params = array(
4274                    'order' => isset($data['order']) ? $data['order'] : 0,
4275                    'limit' => $perPage,
4276                    'offset' => $data['page'] * $perPage,
4277                    'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4278                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4279                    'lang' => $this->localizeDir
4280                );
4281                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
4282                $options['language_id'] = $reviewLanguage[0];
4283                $options['not_language_ids'] = $reviewLanguage[1] ?? null;
4284                $options['isAvatar'] = ( isset($data['isAvatar']) ) ? 1 : 0 ;
4285                $commentCount = $this->UsersClassEvaluation->getCommentCount($data['teacherId'], $options);
4286
4287                if (isset($data['isAvatar'])) {
4288                    $avatarParams = array(
4289                        'order' => isset($data['order']) ? $data['order'] : 0,
4290                        'limit' => $perPage,
4291                        'offset' => $data['page'] * $perPage,
4292                        'user_id' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
4293                        'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
4294                        'selfReviewsFlg' => false,
4295                        'avatar_id' => isset($data['teacherId']) ? $data['teacherId'] : 0,
4296                        'lang' => $this->localizeDir
4297                    );
4298
4299                    myTools::initializeApiTunnel(array('AvatarTeacherController'));
4300                    $teachersReviews = new AvatarTeacherController();
4301                    $comments = $teachersReviews->getAllAvatarEvaluation($avatarParams);
4302                    //count avatar reviews
4303                    $commentCount = $teachersReviews->getCountAllEvaluation(array("avatar_id" => isset($data['teacherId']) ? $data['teacherId'] : 0, 'lang' => $this->localizeDir));
4304
4305                } elseif ( isset($data['isCounseling']) ) {
4306                    myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
4307                    $teachersReviews = new TeachersCounselorReviewsController();
4308                    $teachersReviews->params = $params;
4309                    $comments = $teachersReviews->getAllCounselEvaluation();
4310                // office teacher
4311                } else {
4312                    myTools::initializeApiTunnel(array('TeachersReviewsController'));
4313                    $teachersReviews = new TeachersReviewsController();
4314                    $params['conditions'] = array(
4315                        'UsersClassEvaluation.teacher_id' => $data['teacherId'],
4316                        'UsersClassEvaluation.approve_flag' => 1,
4317                        'UsersClassEvaluation.user_comment <>' => ''
4318                    );
4319                    $teachersReviews->params = $params;
4320                    $comments = $teachersReviews->getReviews();
4321                }
4322
4323
4324                // - if ajax is from counseling
4325                $view = new View($this, false);
4326                $ctr = 0;
4327                $results = [];
4328                foreach ($comments as $comment) {
4329                    $user = new UserTable($comment['User']);
4330                    $review = new UsersClassEvaluationTable($comment['UsersClassEvaluation']);
4331                    $results[$ctr] = array(
4332                        'id' => $review->id,
4333                        'star' => $view->element('rate', array('rate' => $review->rate)),
4334                        'age' => $user->getAge(),
4335                        'gender' => $user->getGenderComment(),
4336                        'user_comment' => $review->getUserComment(),
4337                        'date' => date('Y-m-d', strtotime($review->getCreatedDate($this->timeDiffSecond)))
4338                    );
4339
4340                    $textbook = $comment['SubTextBook'] ?? null;
4341                    if ($textbook) {
4342                        $notSapuriTextFlg = false;
4343                        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
4344                            $pathLocale = '/'. $this->localizeDir;
4345                        }
4346                        $curTextType = $textbook['textbook_category_type'];
4347                        $textDefaultUrl = $pathLocale."/textbook/page-detail/".$textbook['textbook_category_type_id']."/".$textbook['textbook_connect_id'];
4348                        if (isset($this->studySapuriId)) {
4349                            $notSapuriTextFlg = (isset($this->sapuriTextTypes) && $curTextType != $this->sapuriTextTypes) ? true : false;
4350                        }
4351
4352                        $textbook['textUrl'] = $notSapuriTextFlg ? "javascript:void(0)" : $textDefaultUrl;
4353                        $textbook['textbook_image'] = $textbook['textbook_image'] ?? 'no_image';
4354
4355                        if (empty($textbook['textbook_connect_id'])) {
4356                            $textbook['textUrl'] = 'javascript:void(0)';
4357                            $textbook['textbook_image'] = 'no_image';
4358                            $textbook['textbook_name_lv1'] = '';
4359                            $textbook['textbook_name_lv2'] = '';
4360                            $textbook['textbook_name_lv3'] = '';
4361                        }
4362                    }
4363                    $results[$ctr]['textbook'] = $textbook;
4364
4365                    if ($userId) {
4366                        $results[$ctr]['review_id']  = $review->id;
4367                        $results[$ctr]['like_total'] = $review->like_votes;
4368                        $results[$ctr]['dislike_total'] = $review->dislike_votes;
4369                        $results[$ctr]['voted'] = $comment['UsersReviewVote']['vote'] != '' ? (int)$comment['UsersReviewVote']['vote'] : 0;
4370                    }
4371
4372                    $ctr++;
4373                }
4374            }
4375            $lastPage = (intval($data['page'] * $perPage) + $perPage) >= $commentCount ? true : false;
4376            $this->output($results, $lastPage);
4377        }
4378
4379
4380    private function output($data, $lastPage, $result = 'ok') {
4381        $result = array(
4382                'data' => $data,
4383                'result' => $result,
4384                'lastPage' => $lastPage,
4385            );
4386        echo json_encode($result);
4387        return;
4388    }
4389
4390    /**
4391      * @api {get} /user/waiting/is-can-cancel isCanCancel()
4392      * @apiName isCanCancel
4393      * @apiGroup Waiting
4394      * @apiDescription Checks if the user can cancel a reservation in Native Camp. It returns the status of the cancellation eligibility.
4395      *
4396      * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
4397      * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
4398      * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
4399      * 
4400      * @apiSuccess {Boolean} canCancel Indicates whether the user can cancel the reservation.
4401      *
4402      * @apiSuccessExample {json} Success-Response:
4403      *     {
4404      *         "canCancel": true
4405      *     }
4406      *
4407      * @apiError {String} status The status of the request (NG).
4408      * @apiError {String} message The error message.
4409      *
4410      * @apiErrorExample {json} Error-Response:
4411      *     {
4412      *         "status": "NG",
4413      *         "message": "Invalid request."
4414      *     }
4415      * 
4416      * @apiSampleRequest off
4417      */
4418    public function isCanCancel() {
4419        $this->autoRender = false;
4420        $get = $this->request->query;
4421
4422        // NC-8336
4423        if (
4424            isset($get['userId']) &&
4425            (isset($get['fromCorporateManagement']) || isset($get['fromSapuriTos']))
4426        ) {
4427            // get user data
4428            $this->User->openDBReplica();
4429            $user = $this->User->find('first', [
4430                'conditions' => ['User.id' => $get['userId']],
4431                'recursive' => -1
4432            ]);
4433            $this->User->closeDBReplica();
4434            $user = $user ? $user['User'] : [];
4435        } else {
4436            $get['userId'] = $this->Auth->user('id');
4437            $user = $this->sharedUserData['User'];
4438        }
4439
4440        $get['nc_terminal_type'] = 1; // pc
4441        $get['timeDiffSecond'] = $this->timeDiffSecond;
4442        $get['localizeDir'] = $this->localizeDir;
4443        $get['user'] = $user;
4444
4445        // open tunnel
4446        myTools::initializeApiTunnel(['ReservationController']);
4447
4448        // initialize controller
4449        $rc = new ReservationController();
4450
4451        // set data
4452        $rc->params = $get;
4453
4454        // process
4455        return $rc->isCanCancel();
4456    }
4457
4458    /**
4459     * @api {get} /user/waiting/convertString convertString()
4460     * @apiName convertString
4461     * @apiGroup Waiting
4462     * @apiDescription Converts a given string by disabling HTML tags and returns the result along with an ID name.
4463     *
4464     * @apiBody {String} _string The string to be converted.
4465     * @apiBody {String} id_name The ID name to be returned.
4466     * 
4467     * @apiSuccess {Object} result The result object.
4468     * @apiSuccess {String} result.res The converted string with HTML tags disabled.
4469     * @apiSuccess {String} result.idName The ID name.
4470     *
4471     * @apiSuccessExample {json} Success-Response:
4472     *     {
4473     *         "res": "Converted string",
4474     *         "idName": "exampleId"
4475     *     }
4476     *
4477     * @apiError {String} status The status of the request (NG).
4478     * @apiError {String} message The error message.
4479     *
4480     * @apiErrorExample {json} Error-Response:
4481     *     {
4482     *         "status": "NG",
4483     *         "message": "Invalid request."
4484     *     }
4485     * 
4486     * @apiSampleRequest off
4487     */
4488    public function convertString() {
4489        $this->autoRender = false;
4490        $string = $this->request->query['_string'];
4491        $idName = $this->request->query['id_name'];
4492        return json_encode(array('res' => myTools::disableHTMLTags($string), 'idName' => $idName));
4493    }
4494
4495    //not used function
4496    public function getTextbookOption($flag = '') {
4497        $this->autoRender = false;
4498        $result = array();
4499        $textbook_type = 0;
4500        $lessonNowReservation = false;
4501        $textbook_category_type = 0;
4502        $lesson_text_id = 0;
4503
4504        $userId = $this->Auth->user('id');
4505        $teacherId = $this->request->data['teacher_id'];
4506
4507        // NJ-9489 : check if membership is allowed to display counselor information
4508        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4509        $hideCouselorFromMember = 0;
4510
4511        if (
4512            !$_userPaymentPlan ||
4513            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4514        ) {
4515              $hideCouselorFromMember = 1;
4516        }
4517
4518        $textbookOptionArr = array();
4519        $Textbook = new TextbookController;
4520
4521        # course variable
4522        $getCourseArr = array(
4523            'teacher_id' => $teacherId,
4524            'flag' => $flag,
4525            'user_id' => $userId
4526        );
4527
4528        $course = $this->LessonText->getCourse($getCourseArr);
4529
4530            # User last viewed text book
4531            $getLastArr = array(
4532                'user_id' => $userId,
4533                'type' => 'course',
4534                'teacher_id' => $teacherId,
4535                'flag' => $flag
4536            );
4537            $courseDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4538            $courseId = $courseDefault['courseId'] ?? null;
4539            $curriculumId = $courseDefault['curriculumId'] ?? null;
4540            $lessonTextId = $courseDefault['lessonTextId'] ?? null;
4541
4542        $textbookOptionArr['courseArr'] = $course;
4543        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4544
4545        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4546        $textbookOptionArr['courseCurriculumId'] = $curriculumId;
4547        $textbookOptionArr['courseCurriculumArr'] = $dataSetOption;
4548        $courseCurriculumSelected = $textbookOptionArr['courseCurriculumArr']['Curriculum'][$curriculumId] ?? null;
4549        $textbookOptionArr['courseCurriculumSelected'] = $courseCurriculumSelected['data'][$lessonTextId] ?? null;
4550        $textbookOptionArr['courseCurriculumSelected']['badge'] = isset($courseDefault['textbook_info']['Curriculum']['badge']) ? $courseDefault['textbook_info']['Curriculum']['badge'] : 0;
4551        # category variable
4552        $getCategoryArr = array(
4553            'teacher_id' => $teacherId,
4554            'flag' => $flag,
4555            'user_id' => $userId
4556        );
4557        $category = $this->LessonText->getCategory($getCategoryArr);
4558
4559            # User last viewed text book
4560            $getLastArr = array(
4561                'user_id' => $userId,
4562                'type' => 'category',
4563                'teacher_id' => $teacherId,
4564                'flag' => $flag
4565            );
4566            $categoryDefault = $this->LessonText->getLastViewedBook( $getLastArr );
4567            $classId = $categoryDefault['classId'] ?? null;
4568            $categoryLessonTextId = $categoryDefault['lessonTextId'] ?? null;
4569
4570        $textbookOptionArr['categoryArr'] = $category;
4571        $textbookOptionArr['categorySelected'] = isset($textbookOptionArr['categoryArr'][$classId]) ? $textbookOptionArr['categoryArr'][$classId] : 0;
4572        $textbookArr = $this->LessonText->getTextBookCategory(($textbookOptionArr['categorySelected']['ClassMaster']['id'] ?? null),$userId, $flag);
4573        $textbookOptionArr['categoryClassArr'] = $textbookArr['data'] ?? [];
4574        $textbookOptionArr['categoryClassSelected'] = isset($textbookOptionArr['categoryClassArr'][$categoryLessonTextId]) ? $textbookOptionArr['categoryClassArr'][$categoryLessonTextId] : 0;
4575
4576        # ------ default user textbook in iframe
4577        $defaultTextbookType = 2;
4578        $getLastArr = array(
4579            'user_id' => $userId,
4580            'type' => 'all',
4581            'teacher_id' => $teacherId,
4582            'flag' => $flag
4583        );
4584        $lastBookType = $this->LessonText->getLastViewedBook( $getLastArr );
4585        $defaultTextbookType = $lastBookType['textbook_type'] ?? null;
4586
4587        # - since course is the first option shown
4588        if ( $defaultTextbookType ) {
4589            if ( $defaultTextbookType == 1 ) {
4590                # Course
4591                $defaulClassId = $textbookOptionArr['courseCurriculumSelected']['class_id'] ?? 0;
4592                $defaulChapterId = $textbookOptionArr['courseCurriculumSelected']['chapter_id'] ?? 0;
4593            } else {
4594                # Category
4595                $defaulClassId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['class_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] : 0;
4596                $defaulChapterId = isset($textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id']) ? $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] : 0;
4597            }
4598        } else {
4599            # if the user don't have lastviewed ( Category )
4600            $defaulClassId = $textbookOptionArr['categoryClassSelected']['LessonText']['class_id'] ?? null;
4601            $defaulChapterId = $textbookOptionArr['categoryClassSelected']['LessonText']['chapter_id'] ?? null;
4602        }
4603        //use textbook of the reserve schedule
4604        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?class_id={$defaulClassId}&chapter_id={$defaulChapterId}";
4605        $textbookOptionArr['textbook_type'] = $defaultTextbookType;
4606        $textbookOptionArr['hide_switch'] = false;
4607        # ---------------- iframe end
4608
4609        //set flag for hide counselor textbook
4610        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
4611
4612        $view = new View($this, false);
4613        $result['option'] = $view->element('modal_textbook_selection',array('optionArr' => $textbookOptionArr));
4614        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
4615        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
4616
4617        return json_encode($result);
4618    }
4619
4620    /**
4621     * @api {post} /user/waiting/getAllTextbookOption getAllTextbookOption()
4622     * @apiName getAllTextbookOption
4623     * @apiGroup Waiting
4624     * @apiDescription Retrieves all textbook options for the authenticated user in Native Camp. It returns various information about the available textbooks, including courses, series, and user preferences.
4625     *
4626     * @apiBody {String} [teacher_id] The ID of the teacher.
4627     * @apiBody {String} [flag=all] The environment flag (e.g., lesson_now, reservation).
4628     * @apiBody {String} [live_flag] The live flag.
4629     * @apiBody {String} [action] The action to perform (e.g., setNextTextbookChapter).
4630     * @apiBody {String} [localizeDir] The localization directory.
4631     * @apiBody {String} [connectId] The connect ID of the textbook.
4632     * @apiBody {String} [resFlag] The reservation flag.
4633     * @apiBody {String} [textbook_level] The textbook level.
4634     * @apiBody {Boolean} [favorite_textbook_only=0] Indicates if only favorite textbooks should be retrieved.
4635     * 
4636     * @apiSuccess {Object} result The result object.
4637     * @apiSuccess {String} result.option The HTML content for the textbook options.
4638     * @apiSuccess {Boolean} result.levelFiltered Indicates if the textbooks are filtered by level.
4639     * @apiSuccess {String} result.textbook_default The default textbook URL.
4640     * @apiSuccess {Number} result.textbook_type The type of the textbook (1: Course, 2: Series).
4641     * @apiSuccess {Boolean} result.reservation_flag Indicates if the textbook is for reservation.
4642     * @apiSuccess {Boolean} result.disable_button_flag Indicates if the button should be disabled.
4643     * @apiSuccess {Boolean} result.textbook_live_lesson_flg Indicates if the textbook is for live lessons.
4644     * @apiSuccess {Object} result.user_preset_textbook_data The user preset textbook data.
4645     * @apiSuccess {Number} result.user_preset_textbook_data.id The ID of the textbook category.
4646     * @apiSuccess {Number} result.user_preset_textbook_data.connect_id The connect ID of the textbook.
4647     * @apiSuccess {Number} result.user_preset_textbook_data.sub_cat_id The subcategory ID of the textbook.
4648     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_id The ID of the textbook.
4649     * @apiSuccess {Boolean} result.user_preset_textbook_data.display_flag Indicates if the textbook should be displayed.
4650     * @apiSuccess {Number} result.user_preset_textbook_data.textbook_type The type of the textbook.
4651     * @apiSuccess {Boolean} result.userPresetDisplayFlg Indicates if the user preset display flag is set.
4652     *
4653     * @apiSuccessExample {json} Success-Response:
4654     *     {
4655     *         "option": "<div>Textbook Options</div>",
4656     *         "levelFiltered": false,
4657     *         "textbook_default": "/HtmlTextbook/index?connect_id=123&html_dir=dir&chapter_id=1&isFromModal=1",
4658     *         "textbook_type": 1,
4659     *         "reservation_flag": true,
4660     *         "disable_button_flag": 0,
4661     *         "textbook_live_lesson_flg": true,
4662     *         "user_preset_textbook_data": {
4663     *             "id": 1,
4664     *             "connect_id": 123,
4665     *             "sub_cat_id": 2,
4666     *             "textbook_id": 3,
4667     *             "display_flag": true,
4668     *             "textbook_type": 1
4669     *         },
4670     *         "userPresetDisplayFlg": true
4671     *     }
4672     *
4673     * @apiError {String} status The status of the request (NG).
4674     * @apiError {String} message The error message.
4675     *
4676     * @apiErrorExample {json} Error-Response:
4677     *     {
4678     *         "status": "NG",
4679     *         "message": "Invalid request."
4680     *     }
4681     * 
4682     * @apiSampleRequest off
4683     */
4684    public function getAllTextbookOption() {
4685        // increase time limit
4686        set_time_limit(60);
4687        // increase max execution time
4688        ini_set('max_execution_time', 60);
4689        // inscrease memory limit
4690        myTools::alterPHPMemoryLimit('512M');
4691        $this->autoRender = false;
4692        $result = array();
4693        $textbook_category_type = 0;
4694        $lesson_text_id = 0;
4695        //set user id
4696        $userId = $this->Auth->user('id') ?? false;
4697        $param = array('user_id' => $userId);
4698        $textbookOptionArr = array();
4699        $teacherId = isset($this->request->data['teacher_id'])? $this->request->data['teacher_id'] : null;
4700        $envFlag = isset($this->request->data['flag'])? $this->request->data['flag'] : 'all';
4701        $liveFlag = isset($this->request->data['live_flag']) ? $this->request->data['live_flag'] : null;
4702        $connectIdCourse = $connectIdSeries = null;
4703        $action = (isset($this->request->data['action']) && $this->request->data['action'] == 'setNextTextbookChapter') ? $this->request->data['action'] : null;
4704        $isCourse = false;
4705        $teacherBadgeTextbooks     = array();
4706        $counselorTeacher = 0;
4707        $studentFinishedCallanLevelCheck = ClassRegistry::init('User')->hasFinishedCallanLevelCheck(array(
4708            'user_id' => $userId,
4709            'removeRelatedData' => true
4710        ));
4711
4712        // - if has localize directory
4713        if (isset($this->request->data['localizeDir']) && mb_strlen($this->request->data['localizeDir'])) {
4714            $this->localizeDir = $this->request->data['localizeDir'];
4715        }        
4716
4717        // NJ-5836
4718        // set params
4719        $displayRestrictionParams = array(
4720            'lang' => $this->localizeDir
4721        );
4722
4723        // get display restriction setting
4724        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
4725        
4726        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
4727        $userValidForSSBEDT = $this->userValidForSSBEDT();
4728
4729        //NC-8911: check user if for global course
4730        $isUserForGlobalCourse = false;
4731        if(isset($this->localizeDir) && $this->localizeDir !== Configure::read('default.user_language')) {
4732            $isUserForGlobalCourse = true;
4733        }
4734
4735        // NJ-9489 : check if membership is allowed to display counselor information
4736        $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
4737        $hideCouselorFromMember = 0;
4738
4739        if (
4740            !$_userPaymentPlan ||
4741            in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
4742        ) {
4743          $hideCouselorFromMember = 1;
4744        }
4745
4746        // check for counselor type teacher
4747        if ( $teacherId && $envFlag == "lesson_now" ) {
4748            $this->Teacher->openDBReplica();
4749            $counselorTeacher = $this->Teacher->find('count', array(
4750                'conditions' => array(
4751                    'Teacher.id' => $teacherId,
4752                    'Teacher.counseling_flg' => 1,
4753                    'Teacher.status' => 1
4754                ),
4755                'recursive' => -1
4756            ));
4757            $this->Teacher->closeDBReplica();
4758        }
4759        // filter textbook with teacher badge for dropwdown only : display all textbooks for Textbook page
4760        if ( $teacherId && !$counselorTeacher && $envFlag != "all" ) {
4761            $teacherBadgeTextbooks = ClassRegistry::init('TeacherBadge')->getTeacherBadge(array('teacher_id' => $teacherId, 'flag' => $envFlag));
4762        }
4763
4764        // check if student has reserved entry level
4765        $lessonScheduleModel = ClassRegistry::init('LessonSchedule');
4766        $lessonScheduleModel->clear();
4767        $hasReservedCallanLevelCheck = $lessonScheduleModel->hasReservedCallanLevelCheck(array('user_id' => $userId));
4768
4769        // Default Textbook
4770        $defaultParam = array(
4771            'env_flag' => $envFlag,
4772            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4773            'select_method' => "first",
4774            'teacher_id' => $teacherId,
4775            'user_id' => $userId,
4776            'load_description' => false,
4777            'userValidForSSBEDT' => $userValidForSSBEDT,
4778            'user_locale' => $this->localizeDir,
4779            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4780            'isCouncelor' => $counselorTeacher,
4781            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4782            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4783            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4784            'removeRelatedData' => true,
4785            'displayRestriction' => $displayRestriction,
4786            'fetch_favorite' => true
4787        );
4788
4789        if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId'])) {
4790            $defaultParam['connect_id'] = $this->request->data['connectId'];
4791        }
4792
4793        // - add additional parametes for global textbook
4794        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4795            $defaultParam['user_locale'] = $this->localizeDir;
4796        }
4797        $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4798        // if default textbook category is callan and student has yet to finish callan level check
4799        if (
4800            (isset($defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type']) && $defaultTextbookData['res_data']['TextbookCategory']['textbook_category_type'] == 2)
4801            && (isset($defaultTextbookData['res_data']['Textbook']['callan_level_check']) && !$defaultTextbookData['res_data']['Textbook']['callan_level_check'])
4802            && !$studentFinishedCallanLevelCheck
4803        ) {
4804            $defaultParam['tb_default_levelcheck'] = true;
4805            $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4806
4807        // if not callan
4808        } else {
4809            //  NC-7592 - set next textbook chapter/series within the same category
4810            if ($action !== null && $action === 'setNextTextbookChapter') {
4811                $textbookDatails = isset($defaultTextbookData['res_data']) && isset($defaultTextbookData['res_data']['Textbook']) ? $defaultTextbookData['res_data']['Textbook'] : null;
4812                $textbookConnectDetails = $defaultTextbookData['res_data']['TextbookConnect'] ?? null;
4813                $allTextbookParams = array(
4814                    'category_id' => $textbookConnectDetails['category_id'] ?? null,
4815                    'connect_id' => $textbookConnectDetails['id'] ?? null,
4816                    'subcategory_id' => $textbookConnectDetails['subcategory_id'] ?? null,
4817                    'textbook_main_topic_id' => isset($textbookDatails['main_topic_id']) && $textbookDatails['main_topic_id'] ? $textbookDatails['main_topic_id'] : null,
4818                );
4819                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
4820                // if has next textbook chapter, preset
4821                if (
4822                    is_array($allTextbookChapters) && !is_null($allTextbookChapters)
4823                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
4824                ) {
4825                    $newPresetTextbookConnectId = $allTextbookChapters['next'];
4826                    $saveParams = array('userId' => $userId, 'connectId' => $newPresetTextbookConnectId);
4827                    $saveNextTextbookChapter = $this->saveTextbookPreset($saveParams);
4828                    // pull new default data
4829                    $defaultTextbookData = $this->Textbook->getTextbooks($defaultParam);
4830                }
4831            }
4832        }
4833        $defaultTextbook = $defaultTextbookData['res_data'] ?? [];
4834        $defaultConnectId = $defaultTextbook['TextbookConnect']['id'] ?? null;
4835        $defaultTextbookCategoryId = $defaultTextbook['TextbookCategory']['id'] ?? null;
4836        // course
4837        if (isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 1) {
4838            $connectIdCourse = $defaultTextbook['TextbookConnect']['id'] ?? null;
4839            $isCourse = true;
4840        }
4841        // series
4842        if (isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 2) {
4843            $connectIdSeries = $defaultTextbook['TextbookConnect']['id'] ?? null;
4844        }
4845        // Get all Book
4846        $getAllBookArr = array(
4847            'env_flag' => $envFlag,
4848            'teacher_id' => $teacherId,
4849            'select_method' => 'all',
4850            'mode' => 'combine',
4851            'preset' => 'off',
4852            'user_id' => $userId,
4853            'load_description' => false,
4854            'userValidForSSBEDT' => $userValidForSSBEDT,
4855            'user_locale' => $this->localizeDir,
4856            'isUserForGlobalCourse' => $isUserForGlobalCourse,
4857            'is_course' => $isCourse,
4858            'isCouncelor' => $counselorTeacher,
4859            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4860            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4861            'removeRelatedData' => true,
4862            'displayRestriction' => $displayRestriction,
4863            'ranked_textbook' => ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? false : true,
4864            'fetch_favorite' => true
4865        );
4866
4867        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
4868            $getAllBookArr['textbook_level'] = $this->request->data['textbook_level'];
4869        }
4870        
4871        // NC-7593 add favorites on textbook return
4872        if ($userId) {
4873            $params = array("user_id" => $userId);
4874            $textbookFavData = $this->UserTextbookFavorite->getUserFavoriteTextbooks($params);
4875            $getAllBookArr['textbookFavData'] = $textbookFavData;
4876        }
4877
4878        // - add additional parametes for global textbook
4879        if (isset($this->localizeDir) && in_array($this->localizeDir,Configure::read("global_textbook_support_languages"))) {
4880            $getAllBookArr['user_locale'] = $this->localizeDir;
4881        }
4882
4883        $allBookData = $this->Textbook->getTextbooks($getAllBookArr);
4884        $allBook = $allBookData['res_data'] ?? [];
4885
4886        // course variable
4887        $course = $allBook['course'] ?? [];
4888        $getCoursePresetArr = array(
4889            'env_flag' => 'all',
4890            'textbook_type' => 1,
4891            'select_method' => "first",
4892            'teacher_id' => $teacherId,
4893            'connect_id' => $connectIdCourse,
4894            'user_id' => $userId,
4895            'user_locale' => $this->localizeDir,
4896            'load_description' => false,
4897            'isCouncelor' => $counselorTeacher,
4898            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4899            'joinPreTextbookId' => ( !empty($teacherBadgeTextbooks['textbookIdArray']) && count($teacherBadgeTextbooks['textbookIdArray']) > 100 ) ? true : false,
4900            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4901            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4902            'removeRelatedData' => true,
4903            'displayRestriction' => $displayRestriction,
4904            'fetch_favorite' => true
4905        );
4906        $coursePresetData = $this->Textbook->getTextbooks($getCoursePresetArr);
4907        $coursePreset = $coursePresetData['res_data'] ?? [];
4908
4909        // User last viewed text book
4910        $courseId = $coursePreset['TextbookCategory']['id'] ?? null;
4911        $courseSubCatId = $coursePreset['TextbookSubcategory']['id'] ?? null;
4912        $courseSubCatBadge = isset($coursePreset['TextbookSubcategory']['badge']) && $coursePreset['TextbookSubcategory']['badge'] ? $coursePreset['TextbookSubcategory']['badge'] : null;
4913        $courseConnectId = $coursePreset['TextbookConnect']['id'] ?? null;
4914        $courseLessonTextId = $coursePreset['Textbook']['id'] ?? null;
4915
4916
4917        $textbookOptionArr['courseArr'] = $course;
4918        $textbookOptionArr['courseSelected'] = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4919
4920        $dataSetOption = isset($textbookOptionArr['courseArr'][$courseId]) ? $textbookOptionArr['courseArr'][$courseId] : 0;
4921
4922        $textbookOptionArr['courseSubCatId'] = $courseSubCatId;
4923
4924        $textbookOptionArr['courseSubCatArr'] = $dataSetOption;
4925
4926        $courseSubCatSelected = $textbookOptionArr['courseSubCatArr']['TextbookSubcategory'][$courseSubCatId] ?? null;
4927        $textbookOptionArr['courseSubCatSelected'] = $courseSubCatSelected['textbooks'][$courseConnectId] ?? null;
4928        $textbookOptionArr['courseSubCatSelected']['index_position'] = isset($coursePreset['Textbook']['index_position']) && $coursePreset['Textbook']['index_position'] ? $coursePreset['Textbook']['index_position'] : null;
4929        $textbookOptionArr['courseSubCatSelected']['badge'] = $courseSubCatBadge;
4930
4931        // category variable
4932        $series = $allBook['series'] ?? [];
4933        $getSeriesPresetArr = array(
4934            'env_flag' => 'all',
4935            'textbook_type' => 2,
4936            'select_method' => "first",
4937            'connect_id' => $connectIdSeries,
4938            'user_id' => $userId,
4939            'load_description' => false,
4940            'userValidForSSBEDT' => $userValidForSSBEDT,
4941            'user_locale' => $this->localizeDir,
4942            'isUserForGlobalCourse' => false,
4943            'isCouncelor' => $counselorTeacher,
4944            'isForReservation' => ($envFlag == 'reservation') ? true : false,
4945            'removeRelatedData' => true,
4946            'displayRestriction' => $displayRestriction
4947        );
4948        $seriesPresetData = $this->Textbook->getTextbooks($getSeriesPresetArr);
4949        $seriesPreset = $seriesPresetData['res_data'] ?? [];
4950
4951        // User last viewed text book
4952        $seriesId = $seriesPreset['TextbookCategory']['id'] ?? null;
4953        $seriesSubCatId = $seriesPreset['TextbookSubcategory']['id'] ?? null;
4954        $seriesSubCatBadge = isset($seriesPreset['TextbookSubcategory']['badge']) ? $seriesPreset['TextbookSubcategory']['badge'] : null;
4955        $seriesConnectId = $seriesPreset['TextbookConnect']['id'] ?? null;
4956
4957
4958        $textbookOptionArr['seriesArr'] = $series;
4959        $textbookOptionArr['seriesSpecialArr'] = $series;
4960        $textbookOptionArr['seriesSelected'] = isset($textbookOptionArr['seriesArr'][$seriesSubCatId]) ? $textbookOptionArr['seriesArr'][$seriesSubCatId] : 0;
4961
4962        $textbookOptionArr['seriesSubCatId'] = $seriesSubCatId;
4963        $textbookOptionArr['seriesSubCatSelected'] = $series[$seriesSubCatId] ?? null;
4964        $textbookOptionArr['seriesTextbookArr'] = $series[$seriesSubCatId]['Textbook'] ?? [];
4965        $textbookOptionArr['seriesTextbookSelected'] = $series[$seriesSubCatId]['Textbook'][$seriesConnectId] ?? null;
4966        $textbookOptionArr['seriesTextbookSelected']['index_position'] = $seriesPreset['Textbook']['index_position'] ?? null;
4967        $textbookOptionArr['seriesSubCatSelected']['badge'] = $seriesSubCatBadge;
4968
4969        $getSubcatParams = array(
4970            'reservation_flag' => isset($this->request->data['resFlag'])? $this->request->data['resFlag'] : null,
4971            'teacher_id' => $teacherId,
4972            'category_id' => $defaultTextbookCategoryId,
4973            'env_flag' => $envFlag,
4974            'arrange_data' => "branch",
4975            'user_id' => $userId,
4976            'user_locale' => $this->localizeDir,
4977            'userValidForSSBEDT' => true,
4978            'isCouncelor' => $counselorTeacher,
4979            'studentFinishedCallanLevelCheck' => $studentFinishedCallanLevelCheck,
4980            'studentReservedCallanLevelCheck' => $hasReservedCallanLevelCheck,
4981            'removeRelatedData' => true,
4982            'fetch_favorite' => true
4983        );
4984        $getSubCategoryArr = $this->Textbook->getTextbooks($getSubcatParams);
4985
4986        // TextbookSubcategory
4987        if ( $defaultTextbook && ( isset( $getSubCategoryArr['res_data'] ) && $getSubCategoryArr['res_data'] ) ) {
4988            $subCategoryData = $getSubCategoryArr['res_data'];
4989            $subCategoryId = $defaultTextbook['TextbookSubcategory']['id'] ?? null;
4990            $mainTopicTextbookId = isset($defaultTextbook['Textbook']['id']) && $defaultTextbook['Textbook']['id'] ? $defaultTextbook['Textbook']['id'] : null ;
4991            $textbookMainTopicId = isset($defaultTextbook['Textbook']['main_topic_id']) && $defaultTextbook['Textbook']['main_topic_id'] ? $defaultTextbook['Textbook']['main_topic_id'] : null ;
4992
4993            if ( $this->localizeDir != Configure::read('default.user_language') ) {
4994                $subCategoryName  = isset( $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ) && $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] ? $defaultTextbook['GlobalTextbookSubcategory']['gl_name'] : ( isset($defaultTextbook['TextbookSubcategory']['english_name']) && $defaultTextbook['TextbookSubcategory']['english_name'] ? $defaultTextbook['TextbookSubcategory']['english_name'] : $defaultTextbook['TextbookSubcategory']['name'] ) ;
4995            } else {
4996                $subCategoryName  = $defaultTextbook['TextbookSubcategory']['name'];
4997            }
4998
4999            // check for main topic overide subcategory name for daily news
5000            if ( $mainTopicTextbookId && $textbookMainTopicId ) {
5001                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
5002                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($mainTopicTextbookId,$langId);
5003                if ($textbookMainTopicName) { 
5004                    $subCategoryName = $textbookMainTopicName; 
5005                }
5006            }
5007
5008            $textbookOptionArr['subCategoryData'] = $subCategoryData;
5009            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5010            $textbookOptionArr['subCategoryName'] = $subCategoryName;
5011
5012            if ($envFlag == 'reservation') {
5013            $textbookOptionArr['subCategoryId'] = $subCategoryId;
5014                $textbookOptionArr['selectedSubcatTeacherTotalTextbookBadge'] = (isset($subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'])) ? $subCategoryData[$subCategoryId]['TextbookSubcategory']['teacher_total_textbook_badge'] : 0;
5015            }
5016        }
5017
5018        // check daily news category
5019        $dailyNewsCat = false;
5020        $dailyTopicsCat = false;
5021        $textbookObj = null;
5022        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_news_cat_id.series') ) {
5023            $dailyNewsCat = true;
5024            $textbookObj = $this->Textbook;
5025        }
5026        if ( isset($defaultTextbook['TextbookConnect']['category_id']) && $defaultTextbook['TextbookConnect']['category_id'] == Configure::read('daily_topics_textbook.category_id') ) {
5027            $dailyTopicsCat = true;
5028            $textbookObj = $this->Textbook;
5029        }
5030                $eikenEnable = ( $envFlag == 'lesson_now' && isset($defaultTextbook['TextbookConnect']['category_id']) && in_array($defaultTextbook['TextbookConnect']['category_id'], Configure::read('eiken_category_ids')));
5031        // Textbook chapters
5032
5033        // Course
5034        if ( isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 1 ) {
5035            $textbookChapterArr['textbooks'] = $courseSubCatSelected['textbooks'] ?? [];
5036            $selectedTextbookArr = $textbookOptionArr['courseSubCatSelected'];
5037        }
5038        // Series
5039        if ( isset($defaultTextbook['TextbookCategory']['type_id']) && $defaultTextbook['TextbookCategory']['type_id'] == 2 ) {
5040            $textbookChapterArr['textbooks'] = $textbookOptionArr['seriesTextbookArr'];
5041            $selectedTextbookArr = $textbookOptionArr['seriesTextbookSelected'];
5042        }
5043
5044        $textbookOptionArr['dailyNewsCat'] = $dailyNewsCat;
5045        $textbookOptionArr['dailyTopicsCat'] = $dailyTopicsCat;
5046        $textbookOptionArr['textbookObj'] = $textbookObj;
5047        $textbookOptionArr['courseSubCatArr'] = $textbookChapterArr ?? [];
5048        $textbookOptionArr['courseSubCatSelected'] = $selectedTextbookArr ?? [];
5049        $textbookOptionArr['hasFinishedCallanEntry'] = $studentFinishedCallanLevelCheck;
5050        $textbookOptionArr['textbookCategoryType'] = $defaultTextbook['TextbookCategory']['textbook_category_type'] ?? 0;
5051        $textbookOptionArr['eikenEnable'] = $eikenEnable;
5052        $textbookOptionArr['favorite_textbook_only'] = isset($this->request->data['favorite_textbook_only']) ? $this->request->data['favorite_textbook_only'] : 0;
5053
5054        $defaultDir = $defaultTextbook['Textbook']['html_directory'] ?? null;
5055        $defaultChapId = $defaultTextbook['Textbook']['chapter_id'] ?? null;
5056        $defaultBagde = isset($defaultTextbook['TextbookSubcategory']['badge'])?$defaultTextbook['TextbookSubcategory']['badge']:null;
5057
5058        //use textbook of the reserve schedule
5059        $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1";
5060        $textbookOptionArr['textbook_type'] = isset($defaultTextbook['TextbookCategory']['type_id'])? $defaultTextbook['TextbookCategory']['type_id'] : 0;
5061        $textbookOptionArr['hide_switch'] = ($textbook_category_type == 2);
5062        $textbookOptionArr['teacher_badge'] = $defaultBagde;
5063        $result['disable_button_flag'] = 0;
5064        # ---------------- iframe end
5065
5066        $view = new View($this, false);
5067
5068        //NJ-2601 : NJ-24096
5069        if ($envFlag == 'reservation') {
5070            $selectedDataTextbook = ($textbookOptionArr['textbook_type'] == 1) ? $textbookOptionArr['courseSelected'] : $textbookOptionArr['seriesSubCatSelected'];
5071            $textbookLiveLessonFlg = isset($selectedDataTextbook['TextbookCategory']['live_lesson_flg']) ? $selectedDataTextbook['TextbookCategory']['live_lesson_flg'] : false;
5072            if (isset($this->request->data['connectId']) && !empty($this->request->data['connectId']) && isset($defaultTextbook['TextbookCategory']['display_flag']) && $defaultTextbook['TextbookCategory']['display_flag']) {
5073                $result['user_preset_textbook_data']['id'] = $selectedDataTextbook['TextbookCategory']['id'] ?? null; //cat id
5074                $result['user_preset_textbook_data']['connect_id'] = $selectedTextbookArr['connect_id'] ?? null; //connect id
5075                $result['user_preset_textbook_data']['sub_cat_id'] = isset($selectedDataTextbook['TextbookSubcategory']['id']) ? $selectedDataTextbook['TextbookSubcategory']['id'] : 0;
5076                $result['user_preset_textbook_data']['textbook_id'] = (isset($selectedTextbookArr['connect_id']) && isset($selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id']))
5077                    ? $selectedDataTextbook['Textbook'][$selectedTextbookArr['connect_id']]['id']
5078                    : 0;
5079                $result['user_preset_textbook_data']['display_flag'] = (isset($selectedTextbookArr['connect_id']) && isset($courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag']))
5080                    ? $courseSubCatSelected['textbooks'][$selectedTextbookArr['connect_id']]['display_flag']
5081                    : 0;
5082                $result['user_preset_textbook_data']['textbook_type'] = $textbookOptionArr['textbook_type'];
5083                $result['userPresetDisplayFlg'] = $textbookOptionArr['userPresetDisplayFlg'] = $defaultTextbook['TextbookCategory']['display_flag'];
5084            } else {
5085                $textbookOptionArr['textbook_type'] = 2;
5086                $textbookOptionArr['defaulTextbook'] = "/HtmlTextbook/index?connect_id={$defaultConnectId}&html_dir={$defaultDir}&chapter_id={$defaultChapId}&isFromModal=1&emptyReservationTextbook=1";
5087                $textbookOptionArr['has_reservation_connect_id'] = false;
5088                $result['disable_button_flag'] = 1;
5089            }
5090        }
5091
5092        $textbookOptionArr['all'] = ($envFlag == 'reservation') ? false : true;
5093
5094        // - check if live reservation
5095        if ( $teacherId && $liveFlag ) {
5096            $this->Teacher->openDBReplica();
5097            $liveReservation = $this->Teacher->find('count', array(
5098                'conditions' => array(
5099                    'Teacher.id' => $teacherId,
5100                    'Teacher.live_lesson_flg' => 1,
5101                    'Teacher.status' => 1
5102                ),
5103                'recursive' => -1
5104            ));
5105            $this->Teacher->closeDBReplica();
5106
5107            if ($liveReservation) {
5108                // - disabled textbooks if live_lesson_flg is OFF
5109                if (isset($textbookLiveLessonFlg) && !$textbookLiveLessonFlg) {
5110                    $result['textbook_live_lesson_flg'] = true;
5111                }
5112                $textbookOptionArr['live_reservation'] = true;
5113            }
5114        }
5115
5116
5117        // NJ-33115 prepare bookmark data of new callan textbook
5118        if ($userId) {
5119            $bookmarkSeriesData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[0]); // series bookmark
5120            $bookmarkCourseData = $this->LessonBookmark->getBookmarkData($userId, Configure::read('new_callan_textbook_category_id')[1]); // course bookmark
5121            
5122            $bookmarkSeries = json_decode($bookmarkSeriesData, true);
5123            $bookmarkCourse = json_decode($bookmarkCourseData, true);
5124            if (isset($bookmarkSeries['bookmark_id']) && !empty($bookmarkSeries['bookmark_id'])) {
5125                $textbookOptionArr['bookmark']['series'] = $bookmarkSeries;
5126            }
5127            
5128            if (isset($bookmarkCourse['bookmark_id']) && !empty($bookmarkCourse['bookmark_id'])) {
5129                $textbookOptionArr['bookmark']['course'] = $bookmarkCourse;
5130            }
5131        }
5132
5133        //set flag for hide counselor textbook
5134        $textbookOptionArr['hide_counselor_info'] = $hideCouselorFromMember;
5135        $textbookOptionArr['favorites'] = isset($allBook['favorites']) ? $allBook['favorites'] : false;
5136        $textbookOptionArr['liveFlag'] = $liveFlag;
5137
5138        if (isset($this->request->data['textbook_level']) && !empty($this->request->data['textbook_level'])) {
5139            $textbookOptionArr['textbook_level'] = $this->request->data['textbook_level'];
5140            $result['option'] = $view->element('textbook_category_selection',array(
5141                'courseArr' => isset($textbookOptionArr['courseArr']) ? $textbookOptionArr['courseArr'] : false,
5142                'seriesArr' => isset($textbookOptionArr['seriesArr']) ? $textbookOptionArr['seriesArr'] : false,
5143                'favorites' => isset($textbookOptionArr['favorites']) ? $textbookOptionArr['favorites'] : false,
5144                'liveFlag' => $liveFlag
5145            ));
5146            $result['levelFiltered'] = true;
5147        } else {
5148            $result['option'] = $view->element('modal_textbook_selection_2',array('optionArr' => $textbookOptionArr));
5149            $result['levelFiltered'] = false;
5150        }
5151        
5152        // - set result
5153        $result['textbook_default'] = $textbookOptionArr['defaulTextbook'];
5154        $result['textbook_type'] = $textbookOptionArr['textbook_type'];
5155        $result['reservation_flag'] = $defaultTextbook['TextbookCategory']['reservation_flg'] ?? 0;
5156        
5157        // - return json encoded data
5158        $this->response->type('json');
5159        $this->response->body(json_encode($result));
5160        return $this->response;
5161    }
5162
5163    /**
5164     * @api {post} /user/waiting/saveTexbook saveTextbookPreset()
5165     * @apiName saveTextbookPreset
5166     * @apiGroup Waiting
5167     * @apiDescription Saves the preset textbook for the authenticated user in Native Camp. It returns the status of the save operation and the details of the preset textbook.
5168     *
5169     * @apiBody {String} userId The ID of the user.
5170     * @apiBody {Object} presetParams The preset parameters.
5171     * @apiBody {Boolean} [is_pc_flg=true] Indicates if the request is from a PC.
5172     * @apiBody {String} [lang] The language code.
5173     * @apiBody {Boolean} [bypass_dummy_textbook_checker=true] Indicates if the dummy textbook checker should be bypassed.
5174     * 
5175     * @apiSuccess {Boolean} result Indicates whether the preset textbook was successfully saved.
5176     * @apiSuccess {String} image The image URL of the preset textbook.
5177     * @apiSuccess {String} name The name of the preset textbook.
5178     * @apiSuccess {String} cat_name The category name of the preset textbook.
5179     * @apiSuccess {String} chapter The chapter of the preset textbook.
5180     * @apiSuccess {Number} textbookCategoryTypeId The category type ID of the preset textbook.
5181     *
5182     * @apiSuccessExample {json} Success-Response:
5183     *     {
5184     *         "result": true,
5185     *         "image": "http://example.com/image.jpg",
5186     *         "name": "Textbook Name",
5187     *         "cat_name": "Category Name",
5188     *         "chapter": "Chapter 1",
5189     *         "textbookCategoryTypeId": 1
5190     *     }
5191     *
5192     * @apiError {String} status The status of the request (NG).
5193     * @apiError {String} message The error message.
5194     *
5195     * @apiErrorExample {json} Error-Response:
5196     *     {
5197     *         "status": "NG",
5198     *         "message": "Invalid request."
5199     *     }
5200     * 
5201     * @apiSampleRequest off
5202     */
5203    public function saveTextbookPreset($params = array()) {
5204        $status = false;
5205        $reservation_flg = 0;
5206        $this->autoRender = false;
5207
5208        // set preset params
5209        $presetParams = array(
5210            'is_pc_flg' => true,
5211            'lang' => $this->localizeDir,
5212            'bypass_dummy_textbook_checker'    => true
5213        );
5214
5215        if ($this->request->is('ajax')) {
5216            $data = $this->request->data;
5217
5218            // NJ-5836 set additional preset params
5219            $data['presetParams'] = $presetParams;
5220
5221            //if save succesful get the reservation flg of the textbook
5222            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5223                $status = true;
5224            }
5225
5226            // 8020
5227            $presetParams = array("user_id" => $data['userId'] ?? null);
5228
5229            //add additional parameter in fetching preset textbook
5230            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5231                $presetParams["lang"] = $this->localizeDir;
5232            }
5233
5234            // check if user is valid for Study Sapuri Business English Daily textbooks
5235            if ((isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5236                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5237              ){
5238                $presetParams['userValidForSSBEDT'] = true;
5239            }
5240
5241            //fetch preset
5242            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5243
5244        // request is POST
5245        } else {
5246            $data = $params;
5247
5248            // NJ-5836 set additional preset params
5249            $data['presetParams'] = $presetParams;
5250
5251            //if save succesful get the reservation flg of the textbook
5252            if ($this->UsersLastViewedTextbook->savePresetTextbook($data)) {
5253                $status = true;
5254            }
5255
5256            // 8020
5257            $presetParams = array("user_id" => $data['userId']);
5258
5259            //add additional parameter in fetching preset textbook
5260            if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5261                $presetParams["lang"] = $this->localizeDir;
5262            }
5263
5264            // check if user is valid for Study Sapuri Business English Daily textbooks
5265            if (
5266                (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
5267                ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
5268            ){
5269                $presetParams['userValidForSSBEDT'] = true;
5270            }
5271
5272            //fetch preset
5273            $textbookConnectId = $this->UsersLastViewedTextbook->getPresetTextbook($presetParams);
5274        }
5275        echo json_encode(array(
5276                'result' => $status,
5277                'image' => $textbookConnectId['image'] ?? '',
5278                'name' => $textbookConnectId['name'] ?? '',
5279                'cat_name' => $textbookConnectId['cat_name'] ?? '',
5280                'chapter' => $textbookConnectId['chapter'] ?? '',
5281                'textbookCategoryTypeId' => $textbookConnectId['textbook_info']['TextbookCategory']['type_id'] ?? 0,
5282        ));
5283        return;
5284    }
5285
5286    /**
5287     * @api {get} /user/:language/waiting/callLessonAlertandStartButton callLessonAlertandStartButton()
5288     * @apiName callLessonAlertandStartButton
5289     * @apiGroup Waiting
5290     * @apiDescription Retrieves the lesson alert and start button information for the authenticated user in Native Camp. It returns various information about the lesson status, user eligibility, and more.
5291     *
5292     * @apiParam {String} language The language code for the page.
5293     * 
5294     * @apiBody {String} studentId The ID of the student.
5295     * @apiBody {String} teacherId The ID of the teacher.
5296     * @apiBody {Boolean} counselingFlg Indicates if the lesson is a counseling session.
5297     * @apiBody {Boolean} [emergencyFlg=false] Indicates if the lesson is an emergency lesson.
5298     * @apiBody {Boolean} [isSpViewer=false] Indicates if the viewer is using a special viewer.
5299     * @apiBody {Boolean} [redLamp=false] Indicates if the red lamp is on.
5300     * 
5301     * @apiSuccess {Object} result The result object.
5302     * @apiSuccess {String} result.lesson_alert The HTML content for the lesson alert.
5303     * @apiSuccess {String} result.lesson_start_button The HTML content for the lesson start button.
5304     * @apiSuccess {Number} result.isReserved Indicates if the lesson is reserved (1: Yes, 0: No).
5305     * @apiSuccess {Number} result.unverifiedSMS Indicates if the SMS verification is unverified (1: Yes, 0: No).
5306     * @apiSuccess {Number} result.lessonStartIsNormalLitePLan Indicates if the user is on a normal lite plan (1: Yes, 0: No).
5307     * @apiSuccess {Number} result.studentDelayInSeconds The delay in seconds for the student lesson priority.
5308     *
5309     * @apiSuccessExample {json} Success-Response:
5310     *     {
5311     *         "lesson_alert": "<div>Lesson Alert Content</div>",
5312     *         "lesson_start_button": "<button>Start Lesson</button>",
5313     *         "isReserved": 1,
5314     *         "unverifiedSMS": 0,
5315     *         "lessonStartIsNormalLitePLan": 1,
5316     *         "studentDelayInSeconds": 3000
5317     *     }
5318     *
5319     * @apiError {String} status The status of the request (NG).
5320     * @apiError {String} message The error message.
5321     *
5322     * @apiErrorExample {json} Error-Response:
5323     *     {
5324     *         "status": "NG",
5325     *         "message": "Invalid request."
5326     *     }
5327     * 
5328     * @apiSampleRequest off
5329     */
5330    public function callLessonAlertandStartButton() {
5331        $this->autoRender = false;
5332        $view = new View($this, false);
5333        $get = $this->request->query;
5334        $lessonType = false;
5335        $displayFamilyAlert = false;
5336        $isSpViewer = !empty($get['isSpViewer']) ? 1: 0;
5337        $showTakeBusinessTestModal = false;
5338
5339        // check if teacher and student id exists
5340        if (
5341            !isset($get['studentId']) &&
5342            !isset($get['teacherId']) &&
5343            !isset($get['counselingFlg'])
5344        ) {
5345            throw new Exception("Invalid parameters!");
5346        }
5347
5348        // set vars
5349        $device = false;
5350        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
5351        $studentId = $get['studentId'];
5352        $teacherId = $get['teacherId'];
5353        $counselingFlg = $get['counselingFlg'];
5354        $isEmergencyLesson = (isset($get['emergencyFlg']) && $get['emergencyFlg']) ? true : false;
5355        $isGuestViwer = empty($studentId) ? 1 : 0;
5356        $isMobileView = $this->RequestHandler->isMobile();
5357
5358        $isRedLamp = isset($get['redLamp']) && $get['redLamp'] == "1" ? true : false;
5359        // get the data
5360        $teacherData = $this->Teacher->find('first', array(
5361            'fields' => array(
5362                'Teacher.home_flg',
5363                'Teacher.avatar_flg',
5364                'Teacher.avatar_parent_flg',
5365                'Teacher.avatar_id',
5366                'Teacher.native_speaker_flg',
5367            ),
5368            'conditions' => array(
5369                'Teacher.id' => $teacherId
5370            ),
5371            'recursive' => -1
5372        ));
5373
5374        // NJ-48797
5375        $isAvatarTeacher = isset($teacherData['Teacher']['avatar_flg']) && $teacherData['Teacher']['avatar_flg'] == 1;
5376
5377        if ($isAvatarTeacher) {
5378            $avatarParentFlg = isset($teacherData['Teacher']['avatar_parent_flg']) && $teacherData['Teacher']['avatar_parent_flg'] == 1;
5379        
5380            if (!$avatarParentFlg) {
5381                $getParentAvatarTeacher = $this->Teacher->find('first', array(
5382                    'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
5383                    'conditions' => array(
5384                        'Teacher.id' => $teacherData['Teacher']['avatar_id'],
5385                        'Teacher.avatar_parent_flg' => 1
5386                    ),
5387                    'recursive' => -1
5388                ));
5389            } else {
5390                $getParentAvatarTeacher = $teacherData;
5391            }
5392        }
5393
5394        $param = array(
5395            'homeFlag' => isset($teacherData['Teacher']['home_flg']) ? $teacherData['Teacher']['home_flg'] : null,
5396            'isGuestViwer' => $isGuestViwer
5397        );
5398
5399        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $param);
5400
5401        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : [];
5402        $hasRemainingLife = false;
5403
5404        if (
5405            $liveData &&
5406            $liveData['lesson_started'] &&
5407            !$liveData['lesson_finish'] &&
5408            !$isSpViewer &&
5409            !$isGuestViwer &&
5410            !$isMobileView
5411        ) {
5412
5413            // if api token is not set
5414            if (empty($this->sharedUserData['User']['api_token'])) {
5415
5416                $userApiToken = $this->User->generateAndSaveApiToken($studentId);
5417
5418                // update auth value
5419                $this->Session->write('Auth.User.api_token', $userApiToken);
5420            }
5421
5422            // open tunnel
5423            myTools::initializeApiTunnel(array('ChivoxTrainingController'));
5424
5425            // initialize controller
5426            $ctc = new ChivoxTrainingController();
5427
5428            // set data
5429            $ctc->params = [
5430                'nc_terminal_type' => 1, // pc
5431                'users_api_token' => $this->Auth->user('api_token'),
5432                'is_live_lesson' => 1,
5433                'chat_hash' => isset($liveData['chat_hash']) ? $liveData['chat_hash'] : null
5434            ];
5435
5436            // get remaining life details
5437            $noRemainingLifeDetails = json_decode($ctc->trainings_life_status(), true);
5438
5439            if (isset($noRemainingLifeDetails['error'])) {
5440                throw new Exception($noRemainingLifeDetails['error']['message']);
5441            }
5442
5443            $hasRemainingLife = ($noRemainingLifeDetails['infinite_life_flg'] || $noRemainingLifeDetails['remaining_life'] > 0 || $liveData['lesson_joined']) ? true : false;
5444        }
5445
5446        // check user agent
5447        if (strpos($ua, 'Silk') !== false) {
5448            $device = 'kindle';
5449        } else if (strpos($ua, 'Android') !== false) {
5450            $device = 'andriod';
5451        } else if (strpos($ua, 'iPhone') !== false) {
5452            $device = 'ios';
5453        } else if (strpos($ua, 'iPad') !== false) {
5454            $device = 'ios';
5455        } else if (strpos($ua, 'iPod') !== false) {
5456            $device = 'ios';
5457        } else {
5458            $device = 'pc';
5459        }
5460
5461        //check browser
5462        $unsupportedBorwser = false;
5463        $browser =  $this->request->header('User-Agent');
5464        if (preg_match('/(Edg|Edge)/i',$browser) ) {
5465            $unsupportedBorwser = false;
5466        } elseif (preg_match('/(OPR)/i',$browser)) {
5467            $unsupportedBorwser = true;
5468        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
5469            $unsupportedBorwser = false;
5470        } else if ( 
5471            $isSpViewer
5472            && preg_match('/(iPhone|iPad|iPod|Mozilla)/i',$browser)
5473            && preg_match('/(CriOS|FxiOS)/i',$browser)
5474        ) {
5475            //-- IOS CHROME
5476            $unsupportedBorwser = false;
5477        } else {
5478            $unsupportedBorwser = true;
5479        }
5480
5481        // get the teacher's current status
5482        $queryCondition = array(
5483            'fields' => array(
5484                    'TeacherRankCoin.coins',
5485                    'LessonOnair.id',
5486                    'LessonOnair.teacher_id',
5487                    'LessonOnair.user_id',
5488                    'LessonOnair.lesson_type',
5489                    'LessonOnair.live_lesson_flg'
5490                ),
5491            'joins' => array(
5492                array(
5493                    'type' => 'LEFT',
5494                    'table' => 'teacher_rank_coins',
5495                    'alias' => 'TeacherRankCoin',
5496                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
5497                )
5498            ),
5499            'conditions' => array(
5500                array('Teacher.id' => $teacherId)
5501            ),
5502            'show' => 'first'
5503        );
5504        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
5505
5506        if ($isEmergencyLesson && $this->isStudySapuriTosUser) {
5507            $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
5508            $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
5509            $queryCondition['fields'][] = "(
5510                ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
5511                ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
5512                ) as can_emergency_lesson";
5513            $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
5514                as student_no_next_reservation";
5515        }
5516
5517        $commonTeacherStatusParams = array(
5518            'page_display' => 'listTeacher',
5519            'query_conditions' => $queryCondition
5520        );
5521        $lessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
5522
5523        $teacherStatusStandByDurationFieldStr = '(CASE when TeacherStatus.status = 2 then (TIME_TO_SEC(TIMEDIFF(NOW(), TeacherStatus.created))) else 0 end) as teacher_status_standby_duration';
5524        // teacher_status if login or break
5525        $teacherStatus1 = $this->TeacherStatus->find('first', array(
5526            'fields' => array(
5527                'TeacherStatus.status',
5528                'TeacherStatus.remarks1',
5529                'TeacherStatus.remarks2',
5530                $teacherStatusStandByDurationFieldStr
5531            ),
5532            'conditions' => array('TeacherStatus.teacher_id' => $teacherId)
5533        ));
5534        
5535        $isNotAvatar = isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5536         $isNotCounselor = isset($lessonOnair['Teacher']['counseling_flg']) && $lessonOnair['Teacher']['counseling_flg'] == 1 ? 0 : 1; // set to FALSE/0 if teacher is avatar
5537
5538        $studentRemainingSecondsDelay = 0;
5539        if( $isNotAvatar && $isNotCounselor ) {
5540            if( isset($teacherStatus1[0]['teacher_status_standby_duration']) && $teacherStatus1[0]['teacher_status_standby_duration'] ) {
5541                if( (int)$teacherStatus1[0]['teacher_status_standby_duration'] <= (int)$this->studentLessonPriorityTimeDelayInSeconds ) {
5542                    $studentRemainingSecondsDelay = (int)$this->studentLessonPriorityTimeDelayInSeconds - (int)$teacherStatus1[0]['teacher_status_standby_duration'];
5543                }
5544            }
5545        }
5546
5547        // check if lessonOnair is empty
5548        if (isset($lessonOnair['LessonOnair'])) {
5549            $tmp = (object) $lessonOnair['LessonOnair'];
5550            if (!$tmp->id) {
5551                $lessonOnair['LessonOnair'] = null;
5552            }
5553        }
5554
5555        // pass onairs data
5556        $onair = $lessonOnair['LessonOnair'] ?? [];
5557
5558        // check if lessonOnair contains empty values
5559        if (!empty($onair)) {
5560            $oOnair = new LessonOnairTable($onair);
5561        }
5562
5563        // set onair
5564        if (!empty($teacherStatus1) && empty($onair)) {
5565            $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
5566        }
5567
5568        // if teacher status is '4', disable lesson
5569        if (
5570            isset($teacherStatus1['TeacherStatus']['status']) &&
5571            isset($canLesson['lessonAvailable']) &&
5572            $teacherStatus1['TeacherStatus']['status'] == 4
5573        ) {
5574            $canLesson['lessonAvailable'] = 0;
5575        }
5576
5577        // normal
5578        $resEndTime1 = 25;
5579        $resEndTime2 = 55;
5580        if ( isset($lessonOnair['Teacher']['avatar_flg']) && $lessonOnair['Teacher']['avatar_flg'] == 1 ) {
5581            $resEndTime1 = 19;
5582            $resEndTime2 = 49;
5583            // check if has upcoming reservation
5584            if (
5585                isset($canLesson['nextReservation']) &&
5586                $canLesson['nextReservation'] &&
5587                ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5588                isset($oOnair->status) &&
5589                isset($oOnair->connect_flg) &&
5590                $oOnair->connect_flg = 1
5591            ) {
5592                $canLesson['lessonAvailable'] = 0;
5593            }
5594
5595        }
5596
5597        // check if has upcoming reservation
5598        if (
5599            isset($canLesson['nextReservation']) &&
5600            $canLesson['nextReservation'] &&
5601            ((date("i") <= 29 && date("i") >= $resEndTime1) || (date("i") <= 59 && date("i") >= $resEndTime2)) &&
5602            isset($oOnair->status) &&
5603            isset($oOnair->connect_flg) &&
5604            $oOnair->connect_flg = 1
5605        ) {
5606            $oOnair->status = 2;
5607        }
5608
5609        //get preset textbook or last viewed
5610        $presetParams = array("user_id" => $get['studentId'], 'userValidForSSBEDT' => $this->userValidForSSBEDT());
5611
5612        //add additional parameter in fetching preset textbook
5613        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
5614            $presetParams["lang"] = $this->localizeDir;
5615        }
5616
5617        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
5618        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
5619            # for preset
5620            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
5621            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5622
5623        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
5624            # use last viewed textbook if no preset data.
5625            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
5626            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
5627        }
5628
5629        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
5630        $presetParams['is_pc_flg'] = 1;
5631
5632        # fetch preset
5633        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5634        if(!$preset) {
5635            unset($presetParams['connect_id']);
5636            unset($presetParams['last_opened_date']);
5637            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
5638        }
5639
5640        $lessonData = $preset["textbook_info"] ?? null;
5641        $categoryId = $lessonData["TextbookCategory"]["id"] ?? null;
5642        $categoryTypeId = $lessonData["TextbookCategory"]["type_id"] ?? 0;
5643        $textbookId = $lessonData["Textbook"]["id"] ?? null;
5644        if( $categoryTypeId == 1 ) { // course
5645            $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
5646        } else { // series
5647            $seriesId = $categoryId;
5648        }
5649
5650        // check teacher badge
5651        $checkBadge = $this->TeacherBadge->find("first", array(
5652                "conditions" => array(
5653                    "TeacherBadge.teacher_id" => $get['teacherId'],
5654                    "TeacherBadge.textbook_category_id" => $seriesId
5655                ),
5656                "fields" => array("TeacherBadge.id"),
5657                "recursive" => -1
5658            )
5659        );
5660
5661        $canLessonTextbook = false;
5662        if( $checkBadge || $counselingFlg) {
5663            $canLessonTextbook = true;
5664        }
5665
5666        //check if the preset textbook is doesn't have reserve_flg
5667        $textbookForReservationOnly = isset($preset['reservation_flg']) && !$counselingFlg ? $preset['reservation_flg'] : 0;
5668
5669        //get the textbook course / category
5670        $textbookCategoryName = isset($preset['name']) ? $preset['name'] : '' ;
5671
5672        //get next available schedule
5673        $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
5674        if(isset($canLesson['nextReserve'])) {
5675            $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
5676            $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
5677            $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
5678        }
5679
5680        //lesson type in lesson onair is reserved or there is a current reservation
5681        $this->LessonSchedule->recursive = 0;
5682        $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
5683        $isReserved = ((isset($lessonOnair['LessonOnair']['lesson_type']) && $lessonOnair['LessonOnair']['lesson_type'] == 2)
5684                                        || $reservedLessonData && ($reservedLessonData['Teacher']['id'] == $teacherId)) ? true : false;
5685        $corporateIndividualUser = false;
5686        $lessonOrangeButtonRemaining = false;
5687        $showNativeSpeakerWarning = false;
5688        if ($this->Auth->User('id')) {
5689            $userOnairData = $this->LessonOnair->find('first', array(
5690                'conditions' => array(
5691                    'LessonOnair.user_id' => $this->Auth->User('id'),
5692                    'LessonOnair.status' => Configure::read("lesson.status.lesson")
5693                )
5694            ));
5695
5696            $userDuplicateLesson = false;
5697            $lessonOnOther = false;
5698            $userNotEligible = false;
5699            $uOnair = isset($userOnairData['LessonOnair']) ? $userOnairData['LessonOnair']: '';
5700
5701            if ($uOnair != null) {
5702                $uOOnair = new LessonOnairTable($uOnair);
5703                //check user duplicate lesson
5704                if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
5705                    $userDuplicateLesson = true;
5706                    $lessonType = $uOOnair->lesson_type;
5707                }
5708                //check lesson on others
5709                if (isset($oOnair) && $oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
5710                    $lessonOnOther = true;
5711                }
5712            }
5713
5714            //NC-6310 check user have reservation
5715            $nextReservation = LessonScheduleTable::getReservation(array(
5716                'LessonSchedule.teacher_id' => $teacherId,
5717                'LessonSchedule.user_id' =>  $this->sharedUserData['User']['id']
5718            ));
5719
5720            //check user if free or failed
5721            $user = $this->sharedUserData;
5722            $userTable = new UserTable($user['User']);
5723            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
5724            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
5725            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
5726            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
5727            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
5728
5729            // if corporate user
5730            if (isset($user['User']['corporate_id'])) {
5731                $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
5732                $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
5733
5734                // NJ-3660: if 20th day onwards of the month, check if corporate user must take business test
5735                $corporateUserDate = time();
5736                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
5737                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
5738                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
5739
5740                // if user has not yet taken the monthly test and must flag is 1
5741                // and not a reserved lesson and current date is 20+ of the month
5742                $showTakeBusinessTestModal = false;
5743                if (
5744                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
5745                    !$isReserved &&
5746                    (
5747                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
5748                        (
5749                            $userAdminFlag == 1 ||
5750                            (
5751                                isset($user["User"]["nickname"]) &&
5752                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
5753                            )
5754                        )
5755                    )
5756                ) {
5757                    $showTakeBusinessTestModal = true;
5758                }
5759            }
5760
5761            // NC-5409 : Corporate Limited Plan
5762            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
5763            if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
5764
5765                // check if legible
5766                if (( ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) || (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5767                        $userDuplicateLesson || $unsupportedBorwser ||
5768                        $lessonOnOther
5769                ) && $studentId) {
5770                    $userNotEligible = true;
5771                }
5772
5773            } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
5774
5775                $corpLightCondition1 = (
5776                    ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
5777                    (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5778                    $userDuplicateLesson ||
5779                    $unsupportedBorwser ||
5780                    $lessonOnOther
5781                );
5782                // check if legible
5783                if ( $corpLightCondition1 && $studentId) {
5784                    $userNotEligible = true;
5785                }
5786            } elseif (
5787                (
5788                    isset($lessonOnair['Teacher']['native_speaker_flg']) &&
5789                    $lessonOnair['Teacher']['native_speaker_flg']
5790                ) &&
5791                (
5792                    $user['User']['native_option'] == null ||
5793                    $user['User']['native_option'] == 0
5794                ) &&
5795                !$isReserved &&
5796                !$tmp->live_lesson_flg &&
5797                !$this->isStudySapuriTosUser
5798            ) {
5799                $userNotEligible = true;
5800                $showNativeSpeakerWarning = true;
5801            } elseif ( // NJ-48797
5802                (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
5803                ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
5804                !$isReserved &&
5805                !$tmp->live_lesson_flg &&
5806                !$this->isStudySapuriTosUser
5807            ) {
5808                $showNativeSpeakerWarning = true;
5809                $userNotEligible = true;
5810            } else {
5811                // check if legible
5812                if (((!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
5813                        $userDuplicateLesson || $unsupportedBorwser || (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
5814                        $lessonOnOther
5815                ) && $studentId) {
5816                    $userNotEligible = true;
5817                }
5818            }
5819            
5820            // show orange button
5821            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBorwser, $canLesson['lessonAvailable'] ?? null);
5822
5823            # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
5824            $isReservedCanSuddenLesson = false;
5825            $isReservedCanLessonViewing = false;
5826            if (
5827                $canLessonTextbook &&             # - can lesson with the textbook
5828                !$textbookForReservationOnly && # - textbook not for reserve only
5829                !$unsupportedBorwser &&         # - supported browser
5830                $userDuplicateLesson &&         # - has lesson with other teacher
5831                $lessonType == Configure::read('lesson.type.reservation') &&
5832                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5833                !$this->isStudySapuriUser &&    # - not sapuri user
5834                ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
5835                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5836                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5837            ) {
5838                $isReservedCanSuddenLesson = true;
5839            }
5840
5841            if (
5842                !$this->isStudySapuriUser &&
5843                $lessonType == Configure::read('lesson.type.reservation') &&
5844                ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
5845            ) {
5846                $isReservedCanLessonViewing = true;
5847            }
5848            
5849            $canMidwayLesson = false;
5850            if (
5851                $canLessonTextbook &&             # - can lesson with the textbook
5852                !$textbookForReservationOnly && # - textbook not for reserve only
5853                !$unsupportedBorwser &&         # - supported browser
5854                $userDuplicateLesson &&         # - has lesson with other teacher
5855                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
5856                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
5857                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
5858            ) {
5859                $canMidwayLesson = true;
5860            }
5861        }
5862
5863        // NC-3755
5864        if (
5865            isset($this->sharedUserData['User']['parent_id']) &&
5866            !is_null($this->sharedUserData['User']['parent_id'])
5867        ) {
5868            $parent = $this->User->find('first', array(
5869                'fields' => array(
5870                    'User.id',
5871                    'User.hash16',
5872                    'User.charge_flg'
5873                ),
5874                'conditions' => array(
5875                    'User.id' => $this->sharedUserData['User']['parent_id']
5876                ),
5877                'recursive' => -1
5878            ));
5879
5880            if ($parent && $parent['User']['charge_flg'] != 1) {
5881                $displayFamilyAlert = true;
5882            }
5883        }
5884        // NC-4544 - check phone verification auth
5885        $verifyCount = $this->PhoneVerifyCheckLog->find('count',array(
5886            'conditions' => array(
5887                'user_id' => $this->Auth->User('id'),
5888                'status' => 0
5889            )
5890        ));
5891
5892
5893        $teacherParams = array(
5894            'type' => 'first',
5895            'args' => array(
5896                'conditions' => array(
5897                    'id' => $teacherId
5898                ),
5899                'recursive' => -1
5900            )
5901        );
5902        $teacherInfo = $this->Teacher->getTeachers($teacherParams);
5903
5904        // set localize url
5905        if (
5906            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
5907            $get['la'] != Configure::read('default.user_language')
5908        ) {
5909            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
5910        } else {
5911            $localizeUrl = myTools::getUrl();
5912        }
5913
5914        $corporateTypes = Configure::read('corporate_type_arr');
5915        // get live lesson coin
5916        $live_lesson_coin = 0;
5917        if (isset($teacherInfo['Teacher']['current_rank_id']) && $teacherInfo['Teacher']['current_rank_id']) {
5918             $live_lesson_coin = $this->LessonOnairsViewer->getLiveLessonCoinPrice(array(
5919                 'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5920             ));
5921         }
5922
5923        # -don't check lesson daily limit if sapuri toS
5924        if (!$this->isStudySapuriTosUser) {
5925            // # NJ-3319
5926            $teacherStudentConnection = $this->TeacherStudentConnection->find('first', array(
5927                'conditions' => array(
5928                    'user_id' => $this->Auth->User('id'),
5929                    'teacher_id' => $teacherId
5930                ),
5931                'fields' => array(
5932                    'daily_lesson_minutes',
5933                    'daily_lesson_last_update',
5934                    'teacher_id'
5935                ),
5936                'recursive' => -1
5937            ));
5938
5939            $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
5940            if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
5941                $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
5942                    'teacher_id' => $teacherId,
5943                    'teacherStudentData' => $teacherStudentData,
5944                    'counseling_flg' => isset($lessonOnair['Teacher']['counseling_flg']) ? $lessonOnair['Teacher']['counseling_flg'] : 0,
5945                    'avatar_flg' => isset($lessonOnair['Teacher']['avatar_flg']) ? $lessonOnair['Teacher']['avatar_flg'] : 0,
5946                    'nickname' => $userTable->nickname,
5947                    'admin_flg' => $userTable->admin_flg,
5948                    'isReserved' => $isReserved,
5949                    'type' => 1
5950                ));
5951            }
5952        }
5953
5954        $resetTimeLocal = TimezoneTable::computeTimeToUser(array(
5955            'time' => strtotime(date("Y-m-d 00:00:00")),
5956            'timestamp' => $this->timeDiffSecond,
5957            'format' => 'H:i'
5958        ));
5959
5960        // NJ-51 : Set delay for student lesson priority group
5961        $studentLessonPriorityTimeDelay = 0;
5962        $studentDelayInSeconds = 0;
5963
5964        if( $isNotAvatar && $isNotCounselor ) {
5965            if( isset($oOnair) && $oOnair && $oOnair->status == 1 && $oOnair->user_id == null ) {
5966                $studentLessonPriorityTimeDelay = $this->User->userPriorityDelay( array( 'user_id' => $this->Auth->user('id') ) );
5967                if( $studentLessonPriorityTimeDelay ){
5968                    $studentDelayInSeconds = (int) $studentLessonPriorityTimeDelay * 1000;
5969                }
5970            }
5971        }
5972
5973        $result['studentDelayInSeconds'] = $studentDelayInSeconds;
5974
5975        $hasOtherReserved = false;
5976        //- check if reservation is not by the current teacher
5977        if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
5978            $hasOtherReserved = true;
5979        }
5980
5981        $sapuriCoin = 0;
5982        if ($this->isStudySapuriUser) {
5983            $teacherParams = array(
5984                'teacher_id' => $teacherId,
5985                'current_rank_id' => $teacherInfo['Teacher']['current_rank_id']
5986            );
5987            $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
5988        }
5989
5990        # ~ check cannot emergency lesson
5991        $canEmergencyLesson = false;
5992        $emergencyBreakTime = ['status' => false];
5993        if (
5994            $isEmergencyLesson && 
5995            $this->isStudySapuriTosUser &&
5996            !$isReserved &&
5997            isset($lessonOnair[0]['can_emergency_lesson']) && 
5998            isset($lessonOnair[0]['student_no_next_reservation']) && 
5999            $lessonOnair[0]['can_emergency_lesson'] &&         # -can emergency
6000            $lessonOnair[0]['student_no_next_reservation']    # - no next reservation
6001        ) {
6002            $canEmergencyLesson = true;
6003        }
6004
6005        # ~if emergency lesson break time
6006        $currentMinutes = date("i");
6007        $currentHour = date("H");
6008        if ( $isEmergencyLesson && !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
6009            $canEmergencyLesson = false;
6010            $emergencyBreakTime['status'] = true;
6011            $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
6012            $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
6013        }
6014
6015        # ~no sudden lesson for sapuri toS user
6016        if ($this->isStudySapuriTosUser && !$isReserved) {
6017            $userNotEligible = true;
6018        }
6019
6020        $remainingLessonTime = 0;
6021        if( $isNotAvatar && $isNotCounselor && isset($oOnair->end_time)) {
6022            $remainingLessonTimeInSeconds = strtotime($oOnair->end_time)-strtotime('now');
6023            $remainingLessonTime = $remainingLessonTimeInSeconds <= 0 ? 0 : $remainingLessonTimeInSeconds;
6024        }
6025
6026    
6027        #NJ-18780: check for lite plan sudden lesson 
6028        // - check if reserved lesson
6029        $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
6030
6031        $isNormalLitePlanUser = (in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan') ) ) ? true : false;
6032
6033        if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
6034
6035            # disable the lesson button for lite plan if it is not reserved lesson
6036            $userNotEligible = true;
6037
6038            # add if reserve is still ongoing 
6039            if ($isReserved) {
6040                $userNotEligible =false;
6041            }
6042        }
6043
6044        // NJ-29831: check if user has reserved lesson for the next 5 min
6045        $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id'] ?? null);
6046        $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
6047        $hasLessonBeforeActualTime = false;
6048        if (isset($scheduleReservationData) && !empty($scheduleReservationData) && !$onGoingLesson) {
6049            $hasLessonBeforeActualTime = $isReserved = true;
6050        }
6051
6052        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
6053        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($userTable->payment_plan_id);
6054
6055        $redirectPlanUrl = '';
6056        $use7DaysTrialModal = false;
6057        $baseUrl = myTools::getUrl($this->localizeDir);
6058
6059        // if failed settlement -> paid or corporate individual (standard/premium)
6060        if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
6061            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
6062        // if free 
6063        } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
6064            $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
6065        // if free (trial not yet conducted)
6066        } elseif ($this->userMembershipType == 13) {
6067            $userNotEligible = true;
6068            $use7DaysTrialModal = true;
6069        // if corporate company settlement failed -> standard/premium or
6070        } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
6071            $redirectPlanUrl = $baseUrl . '/account/contract_information';
6072        }
6073
6074        $teacherLeaveNotice = '';
6075        $checkNextSchedule = isset($checkNextSchedule) ? $checkNextSchedule : false;
6076        $checkScheduleCurrent = isset($checkScheduleCurrent) ? $checkScheduleCurrent : false;
6077        $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
6078
6079        // NC-5554 : @modified. add trappings for meal break,
6080        // and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
6081        if (
6082            (((isset($canLesson['lessonAvailable']) && $canLesson['lessonAvailable'])
6083            && !$checkNextSchedule 
6084            && $checkScheduleCurrent)
6085            || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
6086            && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
6087            && !$isEmergencyLesson  # ~don't show in emergency page
6088            && !$this->isStudySapuriTosUser
6089            && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
6090            && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
6091        ) {
6092            $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
6093            $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
6094            $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
6095        }
6096
6097
6098        // NJ-56004 - if teacher is logged in and not on standby
6099        $isRedLamp = (isset($teacherStatus1['TeacherStatus']['status']) && $teacherStatus1['TeacherStatus']['status'] == 5) ? true : $isRedLamp;
6100
6101        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
6102        if (
6103            $isReserved && 
6104            (
6105                $this->isStudySapuriUser || 
6106                $this->isStudySapuriTosUser || 
6107                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
6108            )
6109        ) {
6110            $canDoLive = false;
6111        }
6112
6113
6114        // set view vars
6115        $data = array(
6116            'studentLessonPriorityTimeDelayInSeconds' => $studentLessonPriorityTimeDelay,
6117            'studentDelayInSeconds' => $studentDelayInSeconds,
6118            'studentRemainingSecondsDelay' => $studentRemainingSecondsDelay,
6119            'smsThroughFlg' => isset($userTable->sms_through_flg) ? $userTable->sms_through_flg : null,
6120            'verifyCount' => $verifyCount,
6121            'userFailFlag' => isset($userFailFlag)? $userFailFlag : 0,
6122            'userDoubleCheckFlag' => isset($userDoubleCheckFlag)? $userDoubleCheckFlag : 0,
6123            'userCardCompany' => isset($userCardCompany)? $userCardCompany : 0,
6124            'lessonOnOther' => isset($lessonOnOther)? $lessonOnOther : false,
6125            'unsupportedBorwser' => $unsupportedBorwser,
6126            'userDuplicateLesson' => isset($userDuplicateLesson)? $userDuplicateLesson : false,
6127            'lessonType' => $lessonType,
6128            'device' => $device,
6129            'canLesson' => $canLesson,
6130            'userId' => isset($studentId)? $studentId : '',
6131            'teacherId' => $teacherId,
6132            'teacherStatus' => $oOnair ?? [],
6133            'isRedLamp' => $isRedLamp,
6134            'statusCheck' => array(1, 4),
6135            'canLessonTextbook' => $canLessonTextbook,
6136            'isReserved' => $isReserved,
6137            'textbookForReservationOnly' => $textbookForReservationOnly,
6138            'textbookCategoryName' => $textbookCategoryName,
6139            'userNotEligible' => isset($userNotEligible)? $userNotEligible : false,
6140            'reservedLessonData' => $reservedLessonData,
6141            'corporateLimitedPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.limited') ) ,// corporate limited plan
6142            'corporateLightPlan' => (isset($corporateType) && $corporateType == Configure::read('corporate_type.light') ) ,// corporate light plan
6143            'corporateIndividualUser' => $corporateIndividualUser,
6144            'corporateUserFlg' => isset($corporateUserFlg) ? $corporateUserFlg : false,
6145            'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
6146            'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
6147            'checkNextSchedule' => $checkNextSchedule,
6148            'nextSchedule' => $nextSchedule,
6149            'checkScheduleCurrent' => $checkScheduleCurrent,
6150            'displayFamilyAlert' => $displayFamilyAlert,
6151            'nextReservation' => isset($nextReservation) ? $nextReservation : '',
6152            'lessonOnair' => $lessonOnair,
6153            'teacherInfo' => $teacherInfo,
6154            'localizeUrl' => $localizeUrl,
6155            'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
6156            'liveViewCoin' => $live_lesson_coin,
6157            'canDoLive' => $canDoLive,
6158            'points' => $this->UsersPoint->getCurrentUserPoint($userTable->id),
6159            'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
6160            'resetTimeLocal' => $resetTimeLocal == "00:00" ? "24:00" : $resetTimeLocal,
6161            'hasOtherReserved' => $hasOtherReserved,
6162            'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
6163            'isEmergencyLessonPage' => $isEmergencyLesson,
6164            'canEmergencyLesson' => $canEmergencyLesson,
6165            'emergencyBreakTime' => $emergencyBreakTime,
6166            'sapuriCoin' => $sapuriCoin,
6167            'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson ?? false,
6168            'isReservedCanLessonViewing' => $isReservedCanLessonViewing ?? false,
6169            'canMidwayLesson' => $canMidwayLesson ?? false,
6170            'remainingLessonTime' => $remainingLessonTime,
6171            'lessonEndTime' => isset($oOnair->end_time) ? $oOnair->end_time : '',
6172            'isGuestViwer' => $isGuestViwer,
6173            'isMobileView' => $isMobileView,
6174            'isSpViewer' => $isSpViewer,
6175            'lessonStartIsNormalLitePLan' => $isNormalLitePlanUser  ? 1 : 0,
6176            'dummyLessonRoom' => $hasLessonBeforeActualTime,
6177            'isCounselor' => (isset($teacherInfo['Teacher']['counseling_flg']) && $teacherInfo['Teacher']['counseling_flg']) ? true : false,
6178            'redirectPlanUrl' => $redirectPlanUrl,
6179            'use7DaysTrialModal' => $use7DaysTrialModal,
6180            'membershipType' => $this->userMembershipType,
6181            'teacherLeaveNotice' => $teacherLeaveNotice,
6182            'isStudySapuriTosUser' => $this->isStudySapuriUser,
6183            'hasRemainingLife' => $hasRemainingLife
6184        );
6185
6186        // load lesson alert
6187        $result['lesson_alert'] = $view->element('lesson_alert', $data);
6188
6189        // load lesson start button
6190        $result['lesson_start_button'] = $view->element('lesson_start_button', $data);
6191
6192        // reserved flag
6193        $result['isReserved'] = ($isReserved) ? 1 : 0;
6194        $result['unverifiedSMS'] = empty($verifyCount) && empty($userTable->sms_through_flg) ? 1 : 0;
6195
6196        //check if Lite User
6197        $result['lessonStartIsNormalLitePLan'] = $isNormalLitePlanUser ? 1 : 0;
6198
6199        // - set to json
6200        $this->response->type('json');
6201        $this->response->body(json_encode($result));
6202
6203        // return json data
6204        return $this->response;
6205    }
6206
6207    /**
6208     * @api {post} /user/waiting/loadMoreSelfReviews loadMoreSelfReviews()
6209     * @apiName loadMoreSelfReviews
6210     * @apiGroup Waiting
6211     * @apiDescription Loads more self-reviews for a specific teacher and user in Native Camp. It returns the list of self-reviews and indicates if there are more pages available.
6212     *
6213     * @apiBody {Number} [page=2] The page number to load (default is 2).
6214     * @apiBody {String} teacherId The ID of the teacher.
6215     * @apiBody {String} userId The ID of the user.
6216     * 
6217     * @apiSuccess {String} list The HTML list of self-reviews.
6218     * @apiSuccess {Boolean} hasNext Indicates whether there are more pages of self-reviews available.
6219     *
6220     * @apiSuccessExample {json} Success-Response:
6221     *     {
6222     *         "list": "<li>Review 1</li><li>Review 2</li>",
6223     *         "hasNext": true
6224     *     }
6225     *
6226     * @apiError {String} status The status of the request (NG).
6227     * @apiError {String} message The error message.
6228     *
6229     * @apiErrorExample {json} Error-Response:
6230     *     {
6231     *         "status": "NG",
6232     *         "message": "Invalid request."
6233     *     }
6234     * 
6235     * @apiSampleRequest off
6236     */
6237    public function loadMoreSelfReviews() {
6238        $this->autoRender = false;
6239        $list = '';
6240        if ($this->request->is('ajax')) {
6241            $page = isset($this->request->data['page']) ?  $this->request->data['page'] : 2;
6242          $teacherId = isset($this->request->data['teacherId']) ? $this->request->data['teacherId'] : 0;
6243          $userId = isset($this->request->data['userId']) ? $this->request->data['userId'] : 0;
6244            //reviews
6245      $selfReviews = $this->getUserReviews($userId, $teacherId, $page);
6246            $view = new View($this, false);
6247            $list = $view->element('self_comment_list', array('selfReviews' => $selfReviews));
6248        }
6249        return json_encode(
6250            array(
6251                'list' => $list,
6252                'hasNext' => $this->params['paging']['UsersClassEvaluation']['nextPage']
6253            ));
6254    }
6255
6256    /**
6257    * get own user review count and reviews
6258    * @param int user_id
6259    */
6260    private function getUserReviews($userId, $teacherId, $page = 1) {
6261        $this->paginate = array(
6262            'fields' => array(
6263                'UsersClassEvaluation.id',
6264                'UsersClassEvaluation.rate',
6265                'UsersClassEvaluation.user_comment',
6266                'UsersClassEvaluation.created'
6267            ),
6268            'conditions' => array(
6269                    'UsersClassEvaluation.teacher_id' => $teacherId,
6270                    'UsersClassEvaluation.user_id' => $userId,
6271                    'UsersClassEvaluation.rate IS NOT NULL',
6272                ),
6273            'page' => $page,
6274            'limit' => $this->selfReviewLimit,
6275            'order' => 'UsersClassEvaluation.created DESC',
6276            'recursive' => -1
6277        );
6278        return $this->paginate('UsersClassEvaluation');
6279    }
6280
6281    //Retrieves the reservation and cancellation statistics for a specific teacher in Native Camp. It returns the count of reservations and cancellations for the current and previous month, as well as the cancellation rates.
6282    public function getReserveAndCancelled($teacherId) {
6283        //params
6284        $param = array('teacher_id' => $teacherId);
6285
6286        //get count finish reservation and cancelled reservations
6287        $thisMonthReservation = $this->LessonSchedule->getCurrentMonthReservationCount($param);
6288        $lastMonthReservation = $this->LessonSchedule->getLastMonthReservationCount($param);
6289        $thisMonthReservedCancellation = $this->LessonScheduleCancel->getCurrentReservationCancelledCount($param);
6290        $lastMonthReservedCancellation = $this->LessonScheduleCancel->getLastReservationCancelledCount($param);
6291
6292        //get divisors
6293        $lastMonth = strtotime("first day of previous month");
6294        $thisMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId);
6295        $lastMonthLSDivisor = $this->LessonSchedule->getCancellationRateDivisor($teacherId, $lastMonth);
6296        $thisMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId);
6297        $lastMonthLSCDivisor = $this->LessonScheduleCancel->getCancellationRateDivisor($teacherId, $lastMonth);
6298
6299        $thisMonthDivisor = $thisMonthReservation + $thisMonthLSDivisor + $thisMonthLSCDivisor;
6300        $lastMonthDivisor = $lastMonthReservation + $lastMonthLSDivisor + $lastMonthLSCDivisor;
6301
6302        $thisMonthCancellationPercentage = ($thisMonthDivisor == 0) ? 0 : (int)(($thisMonthReservedCancellation / $thisMonthDivisor) * 100);
6303        $lastMonthCancellationPercentage = ($lastMonthDivisor == 0) ? 0 : (int)(($lastMonthReservedCancellation / $lastMonthDivisor) * 100);
6304
6305        return array(
6306            'this_month_reserved' => $thisMonthReservation,
6307            'last_month_reserved' => $lastMonthReservation,
6308            'this_month_cancelled' => $thisMonthReservedCancellation,
6309            'last_month_cancelled' => $lastMonthReservedCancellation,
6310            'this_month_cancellation_rate' => $thisMonthCancellationPercentage,
6311            'last_month_cancellation_rate' => $lastMonthCancellationPercentage
6312        );
6313    }
6314
6315    /**
6316    * shows the orange button after the lesson end
6317    * @param int $userId
6318    * @param int $teacherId
6319    * @param boolean $userNotEligible
6320    * @param boolean $unsupportedBorwser
6321    * @param boolean $canLesson
6322    * @return int $lessonOrangeButtonRemaining
6323    ***/
6324    private function triggerOrangeButton($userId='', $teacherId='', $userNotEligible=false, $unsupportedBorwser=false, $canLesson=false) {
6325        $lessonOrangeButtonRemaining = false;
6326        $secondsRemaining = $this->LessonOnairsLog->getLastLessonSecondsRemaining($userId, $teacherId);
6327        if ($secondsRemaining && !$userNotEligible && !$unsupportedBorwser && $canLesson) {
6328            $lessonOrangeButtonRemaining = $secondsRemaining;
6329        }
6330        return $lessonOrangeButtonRemaining;
6331    }
6332
6333    /**
6334     * @api {post} /user/waiting/deleteLessonOnair deleteLessonOnair()
6335     * @apiName deleteLessonOnair
6336     * @apiGroup Waiting
6337     * @apiDescription Deletes the ongoing lesson on-air information for the authenticated user in Native Camp. It forcefully terminates the lesson if necessary.
6338     *
6339     * @apiBody {Number} [lesson_finish=6] The lesson finish status (default is 6 for force terminate).
6340     * 
6341     * @apiSuccess {Boolean} result Indicates whether the lesson on-air information was successfully deleted.
6342     *
6343     * @apiSuccessExample {json} Success-Response:
6344     *     {
6345     *         "result": true
6346     *     }
6347     *
6348     * @apiError {String} status The status of the request (NG).
6349     * @apiError {String} message The error message.
6350     *
6351     * @apiErrorExample {json} Error-Response:
6352     *     {
6353     *         "status": "NG",
6354     *         "message": "Invalid request."
6355     *     }
6356     * 
6357     * @apiSampleRequest off
6358     */
6359    public function deleteLessonOnair () {
6360        $this->autoRender = false;
6361
6362        // get lesson onair
6363        $lessonOnair = $this->LessonOnair->find('first', array(
6364            'fields' => array(
6365                'LessonOnair.id',
6366                'LessonOnair.lesson_type',
6367                'LessonOnair.leave_lesson'
6368            ),
6369            'conditions' => array(
6370                'LessonOnair.user_id' => $this->Auth->user('id')
6371            ),
6372            'recursive' => -1
6373        ));
6374
6375        // if don't have ongoing lesson onair information
6376        if (!$lessonOnair) {
6377            $this->log("[delete_lesson_onair] has no lesson onair", "debug");
6378            return;
6379        }
6380
6381        // if reserve lesson
6382        if (
6383            !empty($lessonOnair) && // if has lesson onair
6384            $lessonOnair['LessonOnair']['lesson_type'] == 2 // if lesson type is reserve lesson
6385        ) {
6386            // if not yet leave lesson -> force to leave lesson
6387            if ($lessonOnair['LessonOnair']['leave_lesson'] == 0) {
6388                $force_leave_lesson = LessonOnairTable::studentForceLeaveLesson(['lesson_onair_id' => $lessonOnair['LessonOnair']['id']]);
6389                
6390                if (!$force_leave_lesson) {
6391                    throw new Exception('error: Unable to forcefully terminate ongoing lesson ->' . json_encode($lessonOnair));
6392                }
6393            }
6394            // if not normal lesson
6395        } elseif (isset($lessonOnair["LessonOnair"]["lesson_type"]) && $lessonOnair["LessonOnair"]["lesson_type"] != 1) {
6396            throw new Exception('error: not a normal lesson ->' . json_encode($lessonOnair));
6397        }
6398
6399        // log
6400        $this->log("[delete_lesson_onair] deleting lesson onair -> " . json_encode($lessonOnair), "debug");
6401        
6402        $lesson_finish_status = !empty($this->request->data['lesson_finish']) ? $this->request->data['lesson_finish'] : 6; // set lesson finish status, or else set to 6 = force terminate default
6403
6404        // delete lesson oanir
6405        $res = LessonOnairTable::delete($lessonOnair['LessonOnair']['id'], array(), $lesson_finish_status);
6406        
6407        return json_encode(array('result' => $res ? true : false));
6408    }
6409
6410    /**
6411    * get online teachers first page
6412    */
6413    private function getTeacherOnlineList() {
6414        $returnData = array();
6415        $conditionArr = array();
6416        $conditionResult = $this->getSearchCondition();
6417        $conditionResult['conditions'] = array($conditionResult['conditions']);
6418
6419        $commonTeacherStatusParams = array(
6420            'page_display' => 'searchPage',
6421            'query_conditions' => $conditionResult
6422        );
6423        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
6424        
6425        //clear teacher id
6426        $this->Session->delete('waiting-loadedTID');
6427        //save new teacher id
6428        if ($data) {
6429            $teacherId = array();
6430            foreach ($data['TeacherOnlineList'] as $teacher) {
6431                $teacherId[] = $teacher['Teacher']['id'];
6432            }
6433            $this->Session->write('waiting-loadedTID', $teacherId);
6434        }
6435        $returnData['teacherRecordCount'] = $data['teacherRecordCount'];
6436        $returnData['teacherData'] = $data['TeacherOnlineList'];
6437        $returnData['limitGauge'] = $conditionResult['limitGauge']+1;
6438        $returnData['limit'] = $conditionResult['limitCondition'];
6439        return $returnData;
6440    }
6441
6442    /**
6443    * get default search condition
6444    */
6445    private function getSearchCondition() {
6446        //default sort
6447        $sortCondition =  array(
6448            '(select if(count(*) > 0, 1, 0)
6449               FROM lesson_onairs
6450              WHERE teacher_id = Teacher.id AND status = 1 AND connect_flg = 1 LIMIT 1) desc',
6451
6452            '(if ((select if (count(*) > 0, 1, 0)
6453            from teacher_status
6454            where teacher_id = Teacher.id and status = 4 LIMIT 1)
6455
6456            OR
6457
6458            (select if (count(*) > 0, 1, 0)
6459            from lesson_onairs
6460            where teacher_id = Teacher.id and status <> 1 and connect_flg = 1 LIMIT 1), 3, 0)) desc',
6461
6462            'TeacherWeeklyRating.ratings desc',
6463
6464            'Teacher.lesson_count desc',
6465
6466            'Teacher.name asc'
6467        );
6468        //get block teachers id
6469        $blockList = BlockListTable::getBlocks($this->Auth->User('id'), false, 'all');
6470
6471        //default condition
6472        $conditions = array(
6473            'Teacher.id NOT IN' => $blockList,
6474            'Teacher.status' => 1,
6475            'Teacher.admin_flg' => 0,
6476            'Teacher.counseling_flg' => 0,
6477            'Teacher.last_login_time >=' => date('Y-m-d 00:00:00', strtotime('-59 days')),
6478            'LessonOnair.status = 1',
6479            'LessonOnair.connect_flg = 1'
6480        );
6481
6482        // NC-7031
6483        $conditions["AND"]["OR"] = array(
6484            array("Teacher.avatar_parent_flg" => 0, "Teacher.avatar_flg" => 0) // normal teacher
6485        );
6486        //stealth teacher
6487        if ($this->Cookie->read('stealth.setting') != 'on') {
6488            $conditions['Teacher.stealth_flg <>'] = 1;
6489        }
6490
6491        return array(
6492            'conditions' => $conditions,
6493            'sortCondition' => $sortCondition,
6494            'limitGauge' => 1,
6495            'pageLimit' => 80,
6496            'limitCondition' => 80,
6497            'defaultPageLimit' => 80,
6498            'seeMorePageLimit' => 18,
6499            'force_index' => 'FORCE INDEX(last_login_time)'
6500        );
6501    }
6502
6503    //not used function
6504    public function getApologyList($teacher_id = null) {
6505        $cancellesson = $this->LessonScheduleCancel->find('all', array(
6506            'conditions'=>array(
6507                'LessonScheduleCancel.user_id' => $this->Auth->user('id'),
6508                'LessonScheduleCancel.teacher_id' => $teacher_id,
6509#                'LessonScheduleCancel.lesson_time > ' => date('Y-m-d H:i:s'),
6510                'LessonScheduleCancel.status' => Configure::read('reserve_cancel_status_list'),//3 - admin cancel, 4 - system cancel, [24-28] - teacher cancellation, [29-33] - admin cancellation
6511                'LessonScheduleCancel.apology_show' => 1
6512            ),
6513            'fields' => array('LessonScheduleCancel.id', 'LessonScheduleCancel.lesson_time', 'LessonScheduleCancel.user_id','Teacher.id', 'Teacher.name'),
6514            'joins' => array(
6515                    array(
6516                        'type' => 'INNER',
6517                        'table' => 'teachers',
6518                        'alias' => 'Teacher',
6519                        'conditions' => array('Teacher.id = LessonScheduleCancel.teacher_id')
6520                        )
6521                ),
6522            'order' => 'LessonScheduleCancel.id desc'
6523        ));
6524
6525        return $cancellesson;
6526    }
6527
6528    /**
6529     * reservation limit
6530     * @return int
6531     * 1: warning 4th reservation
6532     * 2: 20 lesson reservation only
6533     * 3: 4 reservation only for each teacher
6534     * 4: cancellation limit
6535     * 5: complimentary plan
6536     * 6: corporate light max lesson limit
6537     * 7: lesson request max limit
6538     * 8: eligible for lesson request
6539     */ 
6540
6541     /**
6542     * @api {post} /user/waiting/limit-warning limitwarning()
6543     * @apiName limitwarning
6544     * @apiGroup Waiting
6545     * @apiDescription Checks for reservation limits and warnings for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
6546     *
6547     * @apiBody {String} [userId] The ID of the user (optional if fromCorporateManagement or fromSapuriTos is set).
6548     * @apiBody {Boolean} [fromCorporateManagement] Indicates if the request is from corporate management.
6549     * @apiBody {Boolean} [fromSapuriTos] Indicates if the request is from Sapuri TOS.
6550     * 
6551     * @apiSuccess {String} status The status of the request (OK or NG).
6552     * @apiSuccess {Number} content The content of the response.
6553     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
6554     *
6555     * @apiSuccessExample {json} Success-Response:
6556     *     {
6557     *         "status": "OK",
6558     *         "content": 1,
6559     *         "cancelCount": 2
6560     *     }
6561     *
6562     * @apiError {String} status The status of the request (NG).
6563     * @apiError {Number} content The content of the response.
6564     * @apiError {Number} cancelCount The count of cancellations by the user.
6565     *
6566     * @apiErrorExample {json} Error-Response:
6567     *     {
6568     *         "status": "NG",
6569     *         "content": 0,
6570     *         "cancelCount": 0
6571     *     }
6572     * 
6573     * @apiSampleRequest off
6574     */
6575    public function limitwarning() {
6576        $this->autoRender = false;
6577
6578        if ($this->request->is('post')) {
6579            $post = $this->request->data;
6580
6581            // NC-8336
6582            if (
6583                isset($post['userId']) &&
6584                (isset($post['fromCorporateManagement']) || isset($post['fromSapuriTos']))
6585            ) {
6586                // nothing to do
6587            } else {
6588                $post['userId'] = $this->Auth->user('id');
6589                $post['user'] = $this->sharedUserData['User'];
6590            }
6591
6592            $post['nc_terminal_type'] = 1; // pc
6593            $post['timeDiffSecond'] = $this->timeDiffSecond;
6594 
6595            // open tunnel
6596            myTools::initializeApiTunnel(['ReservationController']);
6597
6598            // initialize controller
6599            $rc = new ReservationController();
6600
6601            // set data
6602            $rc->params = $post;
6603
6604            // process
6605            return $rc->limitWarning();
6606        } else {
6607            return json_encode([
6608                'status' => 'NG',
6609                'content' => 0,
6610                'cancelCount' => 0
6611            ]);
6612        }
6613    }
6614
6615    /**
6616     * @api {post} /user/waiting/updatedScheduleColor updatedScheduleColor()
6617     * @apiName updatedScheduleColor
6618     * @apiGroup Waiting
6619     * @apiDescription Retrieves the updated schedule color information for the authenticated user in Native Camp. It returns the dates when lessons are not available.
6620     *
6621     * @apiBody {String} teacherId The ID of the teacher.
6622     * 
6623     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6624     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6625     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6626     *
6627     * @apiSuccessExample {json} Success-Response:
6628     *     {
6629     *         "disableAll": false,
6630     *         "disabledDays": [
6631     *             "2023-12-01",
6632     *             "2023-12-02"
6633     *         ]
6634     *     }
6635     *
6636     * @apiError {String} status The status of the request (NG).
6637     * @apiError {String} message The error message.
6638     *
6639     * @apiErrorExample {json} Error-Response:
6640     *     {
6641     *         "status": "NG",
6642     *         "message": "Invalid request."
6643     *     }
6644     * 
6645     * @apiSampleRequest off
6646     */
6647    public function updatedScheduleColor() {
6648        $this->autoRender = false;
6649        if ($this->request->is('ajax')) {
6650            $teacherId = $this->request->data['teacherId'];
6651
6652            // NJ-18780 : 
6653            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6654            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
6655
6656            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6657                'userId' => $this->Auth->user('id'),
6658                'teacherId' => $teacherId,
6659                'timeDiff' => $this->timeDiff,
6660                'isNormalLitePlanUser' => $isNormalLitePlanUser
6661            ));
6662            return json_encode($disabledSchedule);
6663        }
6664    }
6665
6666    /**
6667     * @api {post} /user/waiting/getAvatarDisabledDates getAvatarDisabledDates()
6668     * @apiName getAvatarDisabledDates
6669     * @apiGroup Waiting
6670     * @apiDescription Retrieves the disabled dates for avatar lessons for the authenticated user in Native Camp. It returns the dates when avatar lessons are not available.
6671     *
6672     * @apiBody {String} teacherId The ID of the avatar teacher.
6673     * 
6674     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6675     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6676     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6677     *
6678     * @apiSuccessExample {json} Success-Response:
6679     *     {
6680     *         "disableAll": false,
6681     *         "disabledDays": [
6682     *             "2023-12-01",
6683     *             "2023-12-02"
6684     *         ]
6685     *     }
6686     *
6687     * @apiError {String} status The status of the request (NG).
6688     * @apiError {String} message The error message.
6689     *
6690     * @apiErrorExample {json} Error-Response:
6691     *     {
6692     *         "status": "NG",
6693     *         "message": "Invalid request."
6694     *     }
6695     * 
6696     * @apiSampleRequest off
6697     */
6698    public function getAvatarDisabledDates() {
6699        $this->autoRender = false;
6700        if ($this->request->is('ajax')) {
6701            $teacherId = $this->request->data['teacherId'];
6702            $getAvatarParams = array(
6703                "avatar_id" => $teacherId,
6704                "user_id" => $this->Auth->user('id'),
6705                "stealth_flg" => $this->Cookie->read('stealth.setting')
6706            );
6707
6708            // NJ-18780 : 
6709            $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
6710            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans'))) ? true : false;
6711
6712            $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
6713            $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
6714                'userId' => $this->Auth->user('id'),
6715                'teacherId' => $avatarTeacherIds,
6716                'timeDiff' => $this->timeDiff,
6717                'isNormalLitePlanUser' => $isNormalLitePlanUser
6718            ));
6719            return json_encode($disabledSchedule);
6720        }
6721    }
6722
6723    /**
6724     * @api {get} /user/sp/counselor_detail/ sp_counselor()
6725     * @apiName sp_counselor
6726     * @apiGroup Waiting
6727     * @apiDescription Redirects the user to the counselor detail page.
6728     *
6729     * @apiSuccess {String} url The URL to which the user is redirected.
6730     *
6731     * @apiSuccessExample {json} Success-Response:
6732     *     {
6733     *         "url": "https://example.com/user/counselor_detail"
6734     *     }
6735     *
6736     * @apiError {String} status The status of the request (NG).
6737     * @apiError {String} message The error message.
6738     *
6739     * @apiErrorExample {json} Error-Response:
6740     *     {
6741     *         "status": "NG",
6742     *         "message": "Invalid request."
6743     *     }
6744     * 
6745     * @apiSampleRequest off
6746     */
6747    public function sp_counselor() {
6748        return $this->redirect(myTools::getUrl() . '/user/counselor_detail', 301);
6749    }
6750
6751    /**
6752     * @api {get} /user/:language/counselor_detail counselor()
6753     * @apiName counselor
6754     * @apiGroup Waiting
6755     * @apiDescription Retrieves the counselor details for the authenticated user in Native Camp. It returns various information about the user's counselor status, lesson history, and more.
6756     *
6757     * @apiParam {String} language The language code for the page.
6758     * 
6759     * @apiSuccess {Object} teacher The counselor information.
6760     * @apiSuccess {String} teacher.id The ID of the counselor.
6761     * @apiSuccess {String} teacher.name The name of the counselor.
6762     * @apiSuccess {String} teacher.image_url The URL of the counselor's image.
6763     * @apiSuccess {Boolean} isFav Indicates whether the counselor is favorited by the user.
6764     * @apiSuccess {Object} teacherFavsColors The favorite colors for the counselor.
6765     * @apiSuccess {Number} favoriteCount The count of users who have favorited the counselor.
6766     * @apiSuccess {Boolean} isHide Indicates whether the counselor is hidden by the user.
6767     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
6768     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
6769     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
6770     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
6771     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
6772     * @apiSuccess {String} userId The ID of the user.
6773     * @apiSuccess {Object} counselingTable The counseling table information.
6774     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
6775     * @apiSuccess {String} user_lang The native language of the user.
6776     * @apiSuccess {Object} userTimezoneData The user's timezone data.
6777     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
6778     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
6779     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
6780     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
6781     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
6782     * @apiSuccess {String} userCurrentTime The current time of the user.
6783     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
6784     * @apiSuccess {Boolean} canReport Indicates whether the user can report the counselor.
6785     * @apiSuccess {Object} keep_memo The memo kept by the user for the counselor.
6786     * @apiSuccess {String} keep_memo.id The ID of the memo.
6787     * @apiSuccess {String} keep_memo.memo The memo text.
6788     * @apiSuccess {Number} order The order of the reviews.
6789     * @apiSuccess {String} chatHash The chat hash for the lesson.
6790     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
6791     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
6792     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
6793     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
6794     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
6795     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
6796     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
6797     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
6798     * @apiSuccess {Object} user The user information.
6799     * @apiSuccess {String} user.id The ID of the user.
6800     * @apiSuccess {String} user.name The name of the user.
6801     * @apiSuccess {String} user.email The email of the user.
6802     *
6803     * @apiSuccessExample {json} Success-Response:
6804     *     HTTP/1.1 200 OK
6805     *     {
6806     *         "teacher": {
6807     *             "id": "123",
6808     *             "name": "Counselor Name",
6809     *             "image_url": "http://example.com/image.jpg"
6810     *         },
6811     *         "isFav": true,
6812     *         "teacherFavsColors": {...},
6813     *         "favoriteCount": 10,
6814     *         "isHide": false,
6815     *         "isLoggedIn": true,
6816     *         "disabledSchedule": {
6817     *             "disableAll": false,
6818     *             "disabledDays": [
6819     *                 "2023-12-01",
6820     *                 "2023-12-02"
6821     *             ]
6822     *         },
6823     *         "reviewsCount": 5,
6824     *         "userId": "123",
6825     *         "counselingTable": {...},
6826     *         "unsupportedBrowser": false,
6827     *         "user_lang": "en",
6828     *         "userTimezoneData": {
6829     *             "city_eng": "Tokyo",
6830     *             "utc_offset": "+09:00",
6831     *             "country_code_id": 81
6832     *         },
6833     *         "countryTimezone": "Japan",
6834     *         "counselorLampStatus": {...},
6835     *         "userCurrentTime": "2023/12/01 10:00",
6836     *         "login": true,
6837     *         "canReport": true,
6838     *         "keep_memo": {
6839     *             "id": "1",
6840     *             "memo": "This is a memo."
6841     *         },
6842     *         "order": 0,
6843     *         "chatHash": "example_chat_hash",
6844     *         "counselorLessonHistory": [
6845     *             {
6846     *                 "LessonOnairsLog": {
6847     *                     "start_time": "2023-12-01 10:00:00"
6848     *                 }
6849     *             }
6850     *         ],
6851     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
6852     *         "lessonHistoryCount": 5,
6853     *         "latestUserLesson": {
6854     *             "LessonOnairsLog": {
6855     *                 "start_time": "2023-12-01 10:00:00"
6856     *             }
6857     *         },
6858     *         "user": {
6859     *             "id": "123",
6860     *             "name": "John Doe",
6861     *             "email": "john.doe@test.com"
6862     *         }
6863     *     }
6864     *
6865     * @apiError {String} status The status of the request (NG).
6866     * @apiError {String} message The error message.
6867     *
6868     * @apiErrorExample {json} Error-Response:
6869     *     HTTP/1.1 400 Bad Request
6870     *     {
6871     *         "status": "NG",
6872     *         "message": "Invalid request."
6873     *     }
6874     * 
6875     * @apiSampleRequest off
6876     */
6877    public function counselor() {
6878        // NC-9875 start
6879        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi' || $this->localizeDir =='pt-br') {
6880            return $this->redirect(myTools::getUrl());
6881        }
6882
6883        $where = array(
6884            'user_id' => $this->Auth->user('id'),
6885            'teacher_id' => Configure::read('default_counselor_detail')
6886        );
6887
6888        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
6889            return $this->redirect('/mypage');
6890        }
6891
6892        // NC-6615 check if user can report the teacher
6893        $canReport = true;
6894        if (isset($this->sharedUserData['User'])) {
6895            $userData = new UserTable($this->sharedUserData['User']);
6896            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
6897            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
6898            $canReport = $userData->getMembershipTypeIndex();
6899            $membershipIndex = $canReport;
6900            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
6901
6902            //NJ-9489 - redirect to top page if payment type is not allowed
6903            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
6904
6905            // NJ-1454 - redirect to top page if membership type is not allowed
6906            if( !in_array($membershipIndex,$userMemberTypeCanDoCounselingArr) ) {
6907                return $this->redirect(myTools::getUrl());
6908            }
6909
6910            // NJ-9489 - redirect to top page if payment plan is not allowed
6911            if( 
6912                !$_userPaymentPlan ||
6913                in_array($_userPaymentPlan,Configure::read('counselor.not_allowed_payment_plan_id'))
6914             ) {
6915                return $this->redirect(myTools::getUrl());
6916            }
6917        }
6918
6919        // NC-9875 end
6920        $counselor = $this->Teacher->getDefaultCounselorData();
6921        $this->set('teacher', $counselor);
6922
6923        //NJ-20069 counselor
6924        if(!$this->RequestHandler->isMobile()) {
6925            $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null);
6926            $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
6927            $lessonHistoryCount = count($lessonHistory['lessonHistory']);
6928            
6929            $formattedLatestLessonData = "";
6930            if(!empty($latestUserLesson))
6931            $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
6932            
6933            $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
6934            $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
6935            $this->set('lessonHistoryCount', $lessonHistoryCount);
6936            $this->set('latestUserLesson', $latestUserLesson);
6937        }
6938        
6939        //test
6940
6941
6942
6943        # favorite
6944        $where = array(
6945            'UsersFavorite.user_id'     => $this->Auth->user('id'),
6946            'UsersFavorite.teacher_id'     => Configure::read('default_counselor_detail')
6947        );
6948        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
6949        $this->set('isFav', $isFav);
6950        $favIds = $isFav ? [Configure::read('default_counselor_detail')] : [];
6951        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
6952        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
6953            'favIds' => $favIds,
6954            'favIdsTeacherCategory' => $teacherFavColor
6955        ]);
6956        $this->set('teacherFavsColors', $teacherFavsColors);
6957        # count favorite users
6958        $where = array(
6959            'UsersFavorite.teacher_id'  => Configure::read('default_counselor_detail')
6960        );
6961        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
6962        $this->set('favoriteCount', $favoriteCount);
6963
6964        # is teacher hide
6965        $where = array(
6966            'user_id' => $this->Auth->user('id'),
6967            'teacher_id' => Configure::read('default_counselor_detail')
6968        );
6969        $isHide = $this->BlockList->isTeacherHide($where);
6970        $this->set('isHide', $isHide);
6971
6972        //NC-7984 start
6973        $this->set('isLoggedIn', $this->Auth->loggedIn());
6974        $this->counselorLatestLessonHistory($this->Auth->user('id'));
6975        //NC-7984 end
6976
6977        $userId = $this->Auth->user('id');
6978        $counselingTable = $this->CounselingTable;
6979        // - get disabled dates
6980        $counselorIds = $this->Teacher->getCounselorId();
6981        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
6982            'userId' => $userId,
6983            'teacherId' => $counselorIds,
6984            'timeDiff' => $this->timeDiff
6985        ));
6986        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
6987        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
6988        $options['language_id'] = $reviewLanguage[0];
6989        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
6990        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
6991
6992        // - set data to view
6993        $setData = array(
6994            'reviewsCount' => $reviewsCount,
6995            'userId' => $userId,
6996            'disabledSchedule' => json_encode($disabledSchedule),
6997            'counselingTable' => $counselingTable
6998        );
6999        $unsupportedBrowser = false;
7000        $browser = $this->request->header('User-Agent');
7001
7002        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7003            $unsupportedBrowser = true;
7004        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7005            $unsupportedBrowser = false;
7006        } else { 
7007            $unsupportedBrowser = true;
7008        }
7009
7010        $this->set('unsupportedBrowser', $unsupportedBrowser);
7011        $this->set($setData);
7012
7013        if (isset($this->sharedUserData['User'])) {
7014            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7015        }
7016
7017        # get user timezone
7018        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7019        $user_timezone_data = $this->Timezone->find('first',
7020            array(
7021                'fields' => array(
7022                    'Timezone.city_eng',
7023                    'Timezone.utc_offset',
7024                    'Timezone.country_code_id'
7025                ),
7026                'conditions' => array(
7027                    'Timezone.id' => $user_timezone_id
7028                ),
7029                'recursive' => -1
7030            )
7031        );
7032
7033        // - NJ-3653 get country
7034        $countryTimezone = null;
7035        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7036            // - Get all country Code
7037            $countryOptions = $this->Timezone->countryOptions();
7038
7039            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7040            $countryName = $countryOptions[$countryCodeId]['country_name'];
7041
7042            if (isset($countryName) && $countryName) {
7043                $countryTimezone = $countryName;
7044            }
7045        }
7046
7047        // NJ-20272:get counselor lamp status 
7048        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7049
7050        $this->set('countryTimezone', $countryTimezone);
7051        $this->set('userTimezoneData', $user_timezone_data);
7052        $this->set('counselorLampStatus',$counselorLampStatus);
7053
7054        #user time
7055        $datetime = date('Y-m-d H:i:s');
7056        $localTime = $this->displayTime;
7057        // NJ-29496
7058        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7059            $formattedDate = date('d/m/Y G:i', $localTime);
7060        } else {
7061            $formattedDate = date('Y/m/d G:i', $localTime);
7062        }
7063        $this->set('userCurrentTime', $formattedDate);    
7064        $this->set('login', $this->Auth->loggedIn());
7065        $this->set('canReport', $canReport);
7066
7067        $params = array(
7068            'this' => $this,
7069            'forceMobile' => false,
7070            'spView' => '/Mobile/Teacher/counselor_detail',
7071            'view' => '/Waiting/counselor_detail',
7072            'layout' => 'mobile',
7073            'mobile' => null,
7074            'pc' => null
7075        );
7076
7077        //NC-7603 get keep memo
7078        $this->UsersMemo->openDBReplica();
7079        $getKeepMemo = $this->UsersMemo->find('first', array(
7080            'fields' => array(
7081                'id',
7082                'memo'
7083            ),
7084            'conditions' => array(
7085                'user_id' => $this->Auth->user('id'),
7086                'is_counselor' => true
7087            ),
7088            'order' => array('id DESC'),
7089        ));
7090        $this->UsersMemo->closeDBReplica();
7091
7092        // - set keep memo
7093        $this->set('keep_memo', $getKeepMemo);
7094
7095        //set meta for teacher or counselor image 
7096        $counselorObject = new TeacherTable($counselor['Teacher']);
7097        $_teacherImgUrl = $counselorObject->getImageUrl();
7098
7099        //if has image 
7100        if ($_teacherImgUrl) {
7101
7102            //check if teacher has no image 
7103            if (empty($counselorObject->image_url) || !$counselorObject->image_url) {
7104                $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
7105                $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
7106            }
7107
7108            $this->set('meta_teacher_img',$_teacherImgUrl);        
7109        }
7110
7111        
7112        // - set review order
7113        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7114
7115        // class evaluation
7116        if ($this->request->query('chatHash')) {
7117            $chatHash = $this->request->query('chatHash');
7118
7119            // Check if chatHash is valid
7120            $this->LessonOnairsLog->openDBReplica();
7121            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7122            $this->LessonOnairsLog->closeDBReplica();
7123
7124            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7125                $this->LessonOnair->openDBReplica();
7126                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7127                $this->LessonOnair->closeDBReplica();
7128
7129                if(!$allData) {
7130                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7131                }
7132            }
7133
7134            if(!empty($this->sharedUserData['User'])){
7135                // - campaing stamps
7136                $this->getActiveCampaignStampData();
7137            }
7138
7139            $this->set('chatHash', $chatHash);
7140        }
7141        $this->set('counselor_teacher_detail', 1);
7142
7143        // - get user information
7144        $this->User->openDBReplica();
7145        $this->User->recursive = -1;
7146        $data = $this->User->findById($userId);
7147        $this->User->closeDBReplica();
7148
7149        $user = isset($data['User'])?$data['User']: null;
7150        $this->set('counselorObject', $counselorObject);
7151        $this->set('user', $user);
7152        myTools::render($params);
7153    }
7154
7155    /**
7156     * @api {get} /user/customersupport_detail customersupport()
7157     * @apiName customersupport
7158     * @apiGroup Waiting
7159     * @apiDescription Retrieves the customer support details for the authenticated user in Native Camp. It returns various information about the user's customer support status, lesson history, and more.
7160     * 
7161     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
7162     * @apiSuccess {Boolean} isLoggedIn Indicates whether the user is logged in.
7163     * @apiSuccess {Number} reviewsCount The count of reviews for the counselor.
7164     * @apiSuccess {String} userId The ID of the user.
7165     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7166     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7167     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7168     * @apiSuccess {Object} counselingTable The counseling table information.
7169     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
7170     * @apiSuccess {String} user_lang The native language of the user.
7171     * @apiSuccess {Object} userTimezoneData The user's timezone data.
7172     * @apiSuccess {String} userTimezoneData.city_eng The city in English.
7173     * @apiSuccess {String} userTimezoneData.utc_offset The UTC offset.
7174     * @apiSuccess {Number} userTimezoneData.country_code_id The country code ID.
7175     * @apiSuccess {String} countryTimezone The country name based on the user's timezone.
7176     * @apiSuccess {Object} counselorLampStatus The counselor lamp status.
7177     * @apiSuccess {String} userCurrentTime The current time of the user.
7178     * @apiSuccess {Boolean} login Indicates whether the user is logged in.
7179     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
7180     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
7181     * @apiSuccess {String} keep_memo.id The ID of the memo.
7182     * @apiSuccess {String} keep_memo.memo The memo text.
7183     * @apiSuccess {Number} order The order of the reviews.
7184     * @apiSuccess {String} chatHash The chat hash for the lesson.
7185     * @apiSuccess {Object[]} counselorLessonHistory The lesson history of the counselor.
7186     * @apiSuccess {Object} counselorLessonHistory.LessonOnairsLog The lesson on-air log.
7187     * @apiSuccess {String} counselorLessonHistory.LessonOnairsLog.start_time The start time of the lesson.
7188     * @apiSuccess {String} formattedLatestLessonDate The formatted date of the latest lesson.
7189     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
7190     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the counselor.
7191     * @apiSuccess {Object} latestUserLesson.LessonOnairsLog The lesson on-air log.
7192     * @apiSuccess {String} latestUserLesson.LessonOnairsLog.start_time The start time of the lesson.
7193     * @apiSuccess {Object} user The user information.
7194     * @apiSuccess {String} user.id The ID of the user.
7195     * @apiSuccess {String} user.name The name of the user.
7196     * @apiSuccess {String} user.email The email of the user.
7197     *
7198     * @apiSuccessExample {json} Success-Response:
7199     *     {
7200     *         "isHide": false,
7201     *         "isLoggedIn": true,
7202     *         "reviewsCount": 10,
7203     *         "userId": "123",
7204     *         "disabledSchedule": {
7205     *             "disableAll": false,
7206     *             "disabledDays": [
7207     *                 "2023-12-01",
7208     *                 "2023-12-02"
7209     *             ]
7210     *         },
7211     *         "counselingTable": {...},
7212     *         "unsupportedBrowser": false,
7213     *         "user_lang": "en",
7214     *         "userTimezoneData": {
7215     *             "city_eng": "Tokyo",
7216     *             "utc_offset": "+09:00",
7217     *             "country_code_id": 81
7218     *         },
7219     *         "countryTimezone": "Japan",
7220     *         "counselorLampStatus": {...},
7221     *         "userCurrentTime": "2023/12/01 10:00",
7222     *         "login": true,
7223     *         "canReport": true,
7224     *         "keep_memo": {
7225     *             "id": "1",
7226     *             "memo": "This is a memo."
7227     *         },
7228     *         "order": 0,
7229     *         "chatHash": "example_chat_hash",
7230     *         "counselorLessonHistory": [
7231     *             {
7232     *                 "LessonOnairsLog": {
7233     *                     "start_time": "2023-12-01 10:00:00"
7234     *                 }
7235     *             }
7236     *         ],
7237     *         "formattedLatestLessonDate": "2023-12-01 (Fri)",
7238     *         "lessonHistoryCount": 5,
7239     *         "latestUserLesson": {
7240     *             "LessonOnairsLog": {
7241     *                 "start_time": "2023-12-01 10:00:00"
7242     *             }
7243     *         },
7244     *         "user": {
7245     *             "id": "123",
7246     *             "name": "John Doe",
7247     *             "email": "john.doe@test.com"
7248     *         }
7249     *     }
7250     *
7251     * @apiError {String} status The status of the request (NG).
7252     * @apiError {String} message The error message.
7253     *
7254     * @apiErrorExample {json} Error-Response:
7255     *     {
7256     *         "status": "NG",
7257     *         "message": "Invalid request."
7258     *     }
7259     * 
7260     * @apiSampleRequest off
7261     */
7262    public function customersupport() {
7263
7264        // NC-9875 start
7265        if ($this->localizeDir == 'ko' || $this->localizeDir == 'zh-tw' || $this->localizeDir == 'vi') {
7266            return $this->redirect(myTools::getUrl());
7267        }
7268
7269        $isCustomerSupportUser = $this->UsersDetail->isCustomerSupportUser($this->Auth->user('id'));
7270        if(!$isCustomerSupportUser){
7271            return $this->redirect('/mypage');
7272        }
7273
7274        // NJ-54011: Check if user is Free trial not conducted yet.
7275        if ($this->userMembershipType == 13) {
7276            $this->set('membershipType', $this->userMembershipType);
7277        }
7278
7279        $where = array(
7280            'user_id' => $this->Auth->user('id'),
7281            'teacher_id' => Configure::read('default_counselor_detail')
7282        );
7283
7284        if ((BlockListTable::isUserBlocked($where) == true) || ($this->BlockList->isTeacherHide($where) == true)) {
7285            return $this->redirect('/mypage');
7286        }
7287
7288        // NC-6615 check if user can report the teacher
7289        $canReport = true;
7290        if (isset($this->sharedUserData['User'])) {
7291            $userData = new UserTable($this->sharedUserData['User']);
7292            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
7293            $userMemberTypeCanDoCounselingArr = Configure::read('counselor_allowed_membership_index_data');
7294            $canReport = $userData->getMembershipTypeIndex();
7295            $membershipIndex = $canReport;
7296            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
7297            //NJ-9489 - redirect to top page if payment type is not allowed
7298            $_userPaymentPlan = $this->sharedUserData['User']['payment_plan_id'];
7299        }
7300
7301        # is teacher hide
7302        $where = array(
7303            'user_id' => $this->Auth->user('id'),
7304            'teacher_id' => Configure::read('default_customer_support_detail')
7305        );
7306        $isHide = $this->BlockList->isTeacherHide($where);
7307        $this->set('isHide', $isHide);
7308
7309        $counselor = $this->Teacher->getDefaultCustomerSupportDetail();
7310
7311        //NC-7984 start
7312        $this->set('isLoggedIn', $this->Auth->loggedIn());
7313        $this->counselorLatestLessonHistory($this->Auth->user('id'));
7314        //NC-7984 end
7315
7316        $userId = $this->Auth->user('id');
7317        $counselingTable = $this->CounselingTable;
7318        // - get disabled dates
7319        $counselorIds = $this->Teacher->getCounselorId();
7320        $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7321            'userId' => $userId,
7322            'teacherId' => $counselorIds,
7323            'timeDiff' => $this->timeDiff
7324        ));
7325        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
7326        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir);
7327        $options['language_id'] = $reviewLanguage[0];
7328        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
7329        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($counselorIds, $options);
7330
7331        // - set data to view
7332        $setData = array(
7333            'reviewsCount' => $reviewsCount,
7334            'userId' => $userId,
7335            'disabledSchedule' => json_encode($disabledSchedule),
7336            'counselingTable' => $counselingTable
7337        );
7338        $unsupportedBrowser = false;
7339        $browser =  $this->request->header('User-Agent');
7340
7341        if (preg_match('/(OPR|Opera)/i', $browser)) { 
7342            $unsupportedBrowser = true;
7343        } elseif (preg_match('/(Edg|Edge|Chrome|Firefox|Safari)/i', $browser)) { 
7344            $unsupportedBrowser = false;
7345        } else { 
7346            $unsupportedBrowser = true;
7347        }
7348        $this->set('unsupportedBrowser', $unsupportedBrowser);
7349        $this->set($setData);
7350
7351        if (isset($this->sharedUserData['User'])) {
7352            $this->set('user_lang', $this->sharedUserData['User']['native_language2']);
7353        }
7354
7355        # get user timezone
7356        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
7357        $user_timezone_data = $this->Timezone->find('first',
7358            array(
7359                'fields' => array(
7360                    'Timezone.city_eng',
7361                    'Timezone.utc_offset',
7362                    'Timezone.country_code_id'
7363                ),
7364                'conditions' => array(
7365                    'Timezone.id' => $user_timezone_id
7366                ),
7367                'recursive' => -1
7368            )
7369        );
7370
7371        // - NJ-3653 get country
7372        $countryTimezone = null;
7373        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
7374            // - Get all country Code
7375            $countryOptions = $this->Timezone->countryOptions();
7376
7377            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
7378            $countryName = $countryOptions[$countryCodeId]['country_name'];
7379
7380            if (isset($countryName) && $countryName) {
7381                $countryTimezone = $countryName;
7382            }
7383        }
7384
7385        // NJ-20272:get counselor lamp status 
7386        $counselorLampStatus = $this->Teacher->getCounselorLampStatus();
7387
7388        $this->set('countryTimezone', $countryTimezone);
7389        $this->set('userTimezoneData', $user_timezone_data);
7390        $this->set('counselorLampStatus',$counselorLampStatus);
7391
7392        #user time
7393        $datetime = date('Y-m-d H:i:s');
7394        $localTime = $this->displayTime;
7395        // NJ-29496
7396        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
7397            $formattedDate = date('d/m/Y G:i', $localTime);
7398        } else {
7399            $formattedDate = date('Y/m/d G:i', $localTime);
7400        }
7401        $this->set('userCurrentTime', $formattedDate);    
7402        $this->set('login', $this->Auth->loggedIn());
7403        $this->set('canReport', $canReport);
7404
7405        $params = array(
7406            'this' => $this,
7407            'forceMobile' => false,
7408            'spView' => '/Mobile/Teacher/counselor_detail',
7409            'view' => '/Waiting/customersupport_detail',
7410            'layout' => 'mobile',
7411            'mobile' => null,
7412            'pc' => null
7413        );
7414
7415        //NC-7603 get keep memo
7416        $this->UsersMemo->openDBReplica();
7417        $getKeepMemo = $this->UsersMemo->find('first', array(
7418            'fields' => array(
7419                'id',
7420                'memo'
7421            ),
7422            'conditions' => array(
7423                'user_id' => $this->Auth->user('id'),
7424                'teacher_id' => Configure::read('default_customer_support_detail')
7425            ),
7426            'order' => array('id DESC'),
7427        ));
7428        $this->UsersMemo->closeDBReplica();
7429
7430        // - set keep memo
7431        $this->set('keep_memo', $getKeepMemo);
7432
7433        // - set review order
7434        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
7435
7436        // class evaluation
7437        if ($this->request->query('chatHash')) {
7438            $chatHash = $this->request->query('chatHash');
7439
7440            // Check if chatHash is valid
7441            $this->LessonOnairsLog->openDBReplica();
7442            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
7443            $this->LessonOnairsLog->closeDBReplica();
7444
7445            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
7446                $this->LessonOnair->openDBReplica();
7447                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
7448                $this->LessonOnair->closeDBReplica();
7449
7450                if(!$allData) {
7451                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
7452                }
7453            }
7454
7455            if(!empty($this->sharedUserData['User'])){
7456                // - campaing stamps
7457                $this->getActiveCampaignStampData();
7458            }
7459
7460            $this->set('chatHash', $chatHash);
7461        }
7462
7463        $lessonHistory = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), null, true);
7464        $latestUserLesson = ($lessonHistory['lessonHistory'][0]);
7465        $lessonHistoryCount = count($lessonHistory['lessonHistory']);
7466        $lessonHistoryCount = 0;
7467        
7468        $formattedLatestLessonData = "";
7469        if(!empty($latestUserLesson))
7470        $formattedLatestLessonDate = date('Y-m-d',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])). " (" . date('D',strtotime($latestUserLesson['LessonOnairsLog']['start_time'])) . ") ";
7471        
7472        $this->set('counselorLessonHistory', $lessonHistory['lessonHistory']);
7473        $this->set('formattedLatestLessonDate', $formattedLatestLessonDate);
7474        $this->set('lessonHistoryCount', $lessonHistoryCount);
7475        $this->set('latestUserLesson', $latestUserLesson);
7476
7477        // - get user information
7478        $this->User->openDBReplica();
7479        $this->User->recursive = -1;
7480        $data = $this->User->findById($userId);
7481        $this->User->closeDBReplica();
7482
7483        $user = isset($data['User'])?$data['User']: null;
7484        $this->set('teacher', $counselor);
7485        $this->set('user', $user);
7486        $this->set('isCustomerSupportUser', true);
7487         myTools::render($params);
7488        
7489    }
7490
7491    //end of customer support func
7492
7493
7494
7495    /**
7496     * @api {post} /user/waiting/counselingGetDisabledDates counselingGetDisabledDates()
7497     * @apiName counselingGetDisabledDates
7498     * @apiGroup Waiting
7499     * @apiDescription Retrieves the disabled dates for counseling sessions for the authenticated user in Native Camp. It returns the dates when counseling sessions are not available.
7500     *
7501     * @apiBody {String} userId The ID of the user.
7502     * 
7503     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
7504     * @apiSuccess {Boolean} disabledSchedule.disableAll Indicates whether all dates are disabled.
7505     * @apiSuccess {String[]} disabledSchedule.disabledDays The list of disabled dates.
7506     *
7507     * @apiSuccessExample {json} Success-Response:
7508     *     {
7509     *         "disableAll": false,
7510     *         "disabledDays": [
7511     *             "2023-12-01",
7512     *             "2023-12-02"
7513     *         ]
7514     *     }
7515     *
7516     * @apiError {String} status The status of the request (NG).
7517     * @apiError {String} message The error message.
7518     *
7519     * @apiErrorExample {json} Error-Response:
7520     *     {
7521     *         "status": "NG",
7522     *         "message": "Invalid request."
7523     *     }
7524     * 
7525     * @apiSampleRequest off
7526     */
7527    public function counselingGetDisabledDates() {
7528        $this->autoRender = false;
7529        if ($this->request->is('ajax')) {
7530            $data = $this->request->data;
7531            // - get disabled dates
7532            $counselorIds = $this->Teacher->getCounselorId();
7533            $disabledSchedule = $this->LessonSchedule->getDisabledDays(array(
7534                'userId' => $data['userId'],
7535                'teacherId' => $counselorIds,
7536                'timeDiff' => $this->timeDiff
7537            ));
7538            return json_encode($disabledSchedule);
7539        }
7540    }
7541
7542    /**
7543     * @api {post} /user/waiting/counselorSlots counselorSlots()
7544     * @apiName counselorSlots
7545     * @apiGroup Waiting
7546     * @apiDescription Retrieves the available slots for counseling sessions for the authenticated user in Native Camp. It returns the available slots and their states.
7547     *
7548     * @apiBody {String} userId The ID of the user.
7549     * @apiBody {Boolean} [ifForCancellation=false] Indicates whether the request is for cancellation.
7550     * 
7551     * @apiSuccess {Object} schedules The schedules of available slots.
7552     * @apiSuccess {String} schedules.day The day of the week.
7553     * @apiSuccess {String} schedules.d The day of the month.
7554     * @apiSuccess {String} schedules.m The month.
7555     * @apiSuccess {String} schedules.y The year.
7556     * @apiSuccess {Object} schedules.slots The slots for the day.
7557     * @apiSuccess {Number} schedules.slots.open_counselor The number of open counselors.
7558     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by others, 3: Not available, 4: Fully booked, 5: Can't reserve due to limit, 6: Not available within 10 minutes, 7: Available).
7559     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7560     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7561     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7562     * @apiSuccess {Number} [schedules.slots.limited_plan_reservation] Indicates whether the slot is limited plan reservation (if applicable).
7563     *
7564     * @apiSuccessExample {json} Success-Response:
7565     *     {
7566     *         "schedules": {
7567     *             "12/01": {
7568     *                 "day": "(月)",
7569     *                 "d": "01",
7570     *                 "m": "12",
7571     *                 "y": "2023",
7572     *                 "slots": {
7573     *                     "10:00": {
7574     *                         "open_counselor": 2,
7575     *                         "state": 7,
7576     *                         "hour": 10,
7577     *                         "minute": 0,
7578     *                         "is_reserve": false
7579     *                     },
7580     *                     "10:30": {
7581     *                         "open_counselor": 1,
7582     *                         "state": 1,
7583     *                         "hour": 10,
7584     *                         "minute": 30,
7585     *                         "is_reserve": true
7586     *                     }
7587     *                 }
7588     *             }
7589     *         }
7590     *     }
7591     *
7592     * @apiError {String} status The status of the request (NG).
7593     * @apiError {String} message The error message.
7594     *
7595     * @apiErrorExample {json} Error-Response:
7596     *     {
7597     *         "status": "NG",
7598     *         "message": "Invalid request."
7599     *     }
7600     * 
7601     * @apiSampleRequest off
7602     */
7603    public function counselorSlots() {
7604        // $this->autoRender = false;
7605        $data = $this->request->data;
7606        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7607        $user_id = isset($data['userId']) ? $data['userId'] : '';
7608        $this->set('userId', $user_id);
7609        $nowTime = time();
7610        $userTime = $this->displayTime;
7611        $start_date = date('Y-m-d H:i', $nowTime);
7612        $corporateLightUser = false;
7613        $corporateLimitedUser = false;
7614        $slots = array(
7615            'show_caution_flg' => 0,
7616            'start_date' => $start_date,
7617            'states' => NULL
7618        );
7619        // check corporate user
7620        $getCorporateType = $this->User->find("first",array(
7621                "conditions" => array( "User.id" => $user_id ),
7622                "fields" => array("User.payment_plan_id"),
7623                "recursive" => -1,
7624            )
7625        );
7626        
7627        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7628            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7629            
7630            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7631            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7632        }
7633        $this->set('corporateLimitedUser', $corporateLimitedUser);
7634        $this->set('corporateLightUser', $corporateLightUser);
7635        // - if reservation exceeds cancellation already
7636        $sharedUserDataCorporateType = myTools::getCoporateTypeUsingPaymentPlanId($this->sharedUserData['User']['payment_plan_id']);
7637        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7638        $counselorIds = $this->Teacher->getCounselorId();
7639        $result = $this->LessonSchedule->getCounselorSlots(array(
7640            'counselor_ids' => $counselorIds,
7641            'user_id' => $user_id,
7642            'start_day' => $start_date,
7643            'include_past' => true,
7644            'corporateLimitedUser' => $corporateLimitedUser,
7645            'corporateLightUser' => (isset($sharedUserDataCorporateType) && $sharedUserDataCorporateType == Configure::read("corporate_type.light")) ? true : false
7646        ));
7647
7648        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7649        $openSlots = array();
7650        $schedules = array();
7651
7652        if (!$result['error']) {
7653            // - get days
7654            for ($i=0; $i<=7; $i++) {
7655                $cTime = strtotime("+" . $i . " days", $userTime);
7656                $schedDate = date('m/d', $cTime);
7657                $schedules[$schedDate] = array(
7658                    'day' => $weekday[date("w", $cTime)],
7659                    'd' => date('d', $cTime),
7660                    'm' => date('m', $cTime),
7661                    'y' => date('Y', $cTime)
7662                );
7663            }
7664
7665            // - arrange open_slot
7666            foreach ($result['openSlotData'] as $slot) {
7667                $shiftTime = TimezoneTable::computeTimeToUser(array(
7668                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7669                    'timestamp' => $this->timeDiffSecond
7670                ));
7671                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7672                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7673                $lessonHour = date('H', $shiftTime);
7674                $lessonMinute = date('i', $shiftTime);
7675                $lessonDateTime = explode(' ', $formattedLessonTime);
7676                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7677                $lessonDate = date('m/d', strtotime($lessonDate));
7678                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7679
7680                // - state 7 : Available
7681                $state = 7;
7682
7683                //check before 10minutes
7684                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 600) {
7685                    $state = 6;
7686                }
7687
7688                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7689                    'open_counselor' => intval($slot[0]['shiftCount']),
7690                    'state' => $state,
7691                    'hour' => $lessonHour,
7692                    'minute' => $lessonMinute
7693                );
7694
7695                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7696                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7697                }
7698            }
7699
7700            // - counselor ids
7701            $counselorsIds = !empty($counselorIds) ? array_values($counselorIds) : array();
7702            // - counselor reservations
7703            foreach ($result['reservationData'] as $reservation) {
7704                //get timestamp adjusted to user timezone
7705                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7706                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7707                    'timestamp' => $this->timeDiffSecond
7708                ));
7709                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7710                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7711
7712                $lessonHour = date('H', $unixUserLessonTime);
7713                $lessonMinute = date('i', $unixUserLessonTime);
7714                $lessonDateTime = explode(' ', $formattedUserLessonTime);
7715                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7716                $lessonDate = date('m/d', strtotime($lessonDate));
7717                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7718
7719                // - if my reservation
7720                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
7721                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && !empty($openSlots[$timeIndex])) {
7722                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
7723                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $counselorsIds) && empty($openslot[$timeIndex])) {
7724                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
7725                    } else {
7726                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
7727                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7728                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7729                    }
7730
7731                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
7732
7733                // - if not my reservations
7734                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
7735                    $openSlots[$timeIndex]--;
7736
7737                    # to prevent the schedule of the current user being overriden by other users schedules
7738                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
7739                        continue;
7740                    }
7741
7742                    if (
7743                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
7744                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
7745                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
7746                    ) {
7747                        $openSlots[$timeIndex]--;
7748                        // - state 5 : can't reserve because of reservation limit
7749                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7750                            'state' => 5,
7751                            'open_counselor' => intval($openSlots[$timeIndex]),
7752                            'hour' => $lessonHour,
7753                            'minute' => $lessonMinute
7754                        );
7755
7756                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
7757                        // - state 7 : Available
7758                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
7759                            'state' => 7,
7760                            'open_counselor' => intval($openSlots[$timeIndex]),
7761                            'hour' => $lessonHour,
7762                            'minute' => $lessonMinute
7763                        );
7764                    } elseif (
7765                        isset($openSlots[$timeIndex])
7766                        && $openSlots[$timeIndex] <= 0
7767                        && (
7768                            isset($schedules[$formattedLessonTime]['state'])
7769                            && $schedules[$formattedLessonTime]['state'] >= 4
7770                            || empty($schedules[$formattedLessonTime]['state'])
7771                        )
7772                    ) {
7773                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
7774                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
7775                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
7776                    }
7777                }
7778            }
7779
7780            if ($ifForCancellation) {
7781                $this->autoRender = false;
7782                return json_encode($schedules);
7783            }
7784            $this->set('schedules', $schedules);
7785        }
7786    }
7787
7788    /**
7789     * @api {post} /user/waiting/avatarSlots avatarSlots()
7790     * @apiName avatarSlots
7791     * @apiGroup Waiting
7792     * @apiDescription Retrieves the available slots for avatar lessons for the authenticated user in Native Camp. It returns the schedule and availability of the slots.
7793     *
7794     * @apiBody {String} teacherId The ID of the avatar teacher.
7795     * @apiBody {Boolean} [ifForCancellation] Indicates whether the request is for cancellation.
7796     * @apiBody {String} userId The ID of the user.
7797     * 
7798     * @apiSuccess {Object} schedules The schedule and availability of the slots.
7799     * @apiSuccess {String} schedules.day The day of the week.
7800     * @apiSuccess {String} schedules.d The day of the month.
7801     * @apiSuccess {String} schedules.m The month.
7802     * @apiSuccess {String} schedules.y The year.
7803     * @apiSuccess {Object} schedules.slots The slots for each day.
7804     * @apiSuccess {Number} schedules.slots.open_avatar The number of open avatar slots.
7805     * @apiSuccess {Number} schedules.slots.state The state of the slot (1: Reserved by user, 2: Reserved by another user, 3: Reserved by another user and not available, 4: No open slots, 5: Can't reserve because of reservation limit, 6: Can't reserve because it's within 5 minutes, 7: Available).
7806     * @apiSuccess {Number} schedules.slots.hour The hour of the slot.
7807     * @apiSuccess {Number} schedules.slots.minute The minute of the slot.
7808     * @apiSuccess {Object} [schedules.slots.teacherData] The data of the teacher for the slot.
7809     * @apiSuccess {Object} [schedules.slots.ownTeacherData] The data of the user's own teacher for the slot.
7810     * @apiSuccess {Boolean} schedules.slots.is_reserve Indicates whether the slot is reserved by the user.
7811     * @apiSuccess {String} schedules.slots.teacher_id The ID of the teacher for the slot.
7812     * @apiSuccess {Object} campaignPeriod The campaign period for the avatar teacher.
7813     * @apiSuccess {String[]} times The available times for the slots.
7814     *
7815     * @apiSuccessExample {json} Success-Response:
7816     *     {
7817     *         "schedules": {
7818     *             "12/01": {
7819     *                 "day": "(月)",
7820     *                 "d": "01",
7821     *                 "m": "12",
7822     *                 "y": "2023",
7823     *                 "slots": {
7824     *                     "10:00": {
7825     *                         "open_avatar": 2,
7826     *                         "state": 7,
7827     *                         "hour": 10,
7828     *                         "minute": 0
7829     *                     },
7830     *                     "10:30": {
7831     *                         "open_avatar": 1,
7832     *                         "state": 1,
7833     *                         "hour": 10,
7834     *                         "minute": 30,
7835     *                         "ownTeacherData": {
7836     *                             "id": "123",
7837     *                             "name": "John Doe",
7838     *                             "image": "https://www.nativecamp.net/img/teacher/123.jpg"
7839     *                         }
7840     *                     }
7841     *                 }
7842     *             }
7843     *         },
7844     *         "campaignPeriod": {...},
7845     *         "times": ["00:00", "00:30", "01:00", ...]
7846     *     }
7847     *
7848     * @apiError {String} status The status of the request (NG).
7849     * @apiError {Number} content The content of the response (0: No issues).
7850     *
7851     * @apiErrorExample {json} Error-Response:
7852     *     {
7853     *         "status": "NG",
7854     *         "content": 0
7855     *     }
7856     * 
7857     * @apiSampleRequest off
7858     */
7859    public function avatarSlots() {
7860        
7861        $data = $this->request->data;
7862        $teacherId = isset($data['teacherId']) ? $data['teacherId'] : '';
7863        $ifForCancellation = (isset($data['ifForCancellation']) && $data['ifForCancellation']) ? true : false;
7864        $user_id = isset($data['userId']) ? $data['userId'] : '';
7865        $this->set('userId', $user_id);
7866        $this->set('currentAvatarId', $teacherId);
7867        $nowTime = time();
7868        $userTime = $this->displayTime;
7869        $start_date = date('Y-m-d H:i', $nowTime);
7870        $corporateLightUser = false;
7871        $corporateLimitedUser = false;
7872        $slots = array(
7873            'show_caution_flg' => 0,
7874            'start_date' => $start_date,
7875            'states' => NULL
7876        );
7877        // check corporate user
7878        $getCorporateType = $this->User->find("first",array(
7879                "conditions" => array( "User.id" => $user_id ),
7880                "fields" => array("User.payment_plan_id"),
7881                "recursive" => -1,
7882            )
7883        );
7884
7885        if ($getCorporateType && isset($getCorporateType["User"]["payment_plan_id"]) ) {
7886            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($getCorporateType["User"]["payment_plan_id"]);
7887            $corporateLightUser = ($corporateType == Configure::read("corporate_type.light"));
7888            $corporateLimitedUser = ($corporateType == Configure::read("corporate_type.limited"));
7889        }
7890
7891        $this->set('corporateLightUser', $corporateLightUser);
7892        $this->set('corporateLimitedUser', $corporateLimitedUser);
7893        // - if reservation exceeds cancellation already
7894        $slots['show_caution_flg'] = ($this->LessonSchedule->reservationCautionFlag(array('userId' => $user_id))) ? 1 : 0;
7895        $getAvatarParams = array(
7896            "avatar_id" => $teacherId,
7897            "user_id" => $user_id,
7898            "stealth_flg" => $this->Cookie->read('stealth.setting'),
7899            'corporateLimitedUser' => $corporateLimitedUser
7900        );
7901        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
7902        $result = $this->LessonSchedule->getAvatarSlots(array(
7903            'avatar_ids' => $avatarTeacherIds,
7904            'user_id' => $user_id,
7905            'start_day' => $start_date,
7906            'include_past' => true,
7907            'corporateLimitedUser' => $corporateLimitedUser
7908        ));
7909
7910        //campaign period start and end time
7911        $campaignPeriod = null;
7912        $checkAvatarPop = $this->userAvailPopularTeacher(
7913            array(
7914                'avatar_id' => $teacherId,
7915                'user_id' => $this->Auth->user('id'),
7916                "stealth_flg" => $this->Cookie->read('stealth.setting')
7917            )
7918        );
7919        if ($result && $checkAvatarPop) {
7920            $campaignPeriod = $this->PopularTeacherCampaignPeriod->fetchCampaignPeriod(array(
7921                'user_id' => $this->Auth->user('id'),
7922                'teacher_id' => $teacherId
7923            ));
7924        }
7925
7926        $weekday = array( __d('waiting','(日)'), __d('waiting','(月)'), __d('waiting','(火)'), __d('waiting','(水)'), __d('waiting','(木)'), __d('waiting','(金)'), __d('waiting','(土)') );
7927        $openSlots = array();
7928        $schedules = array();
7929        $tempSchedules = array();
7930
7931        if (!$result['error']) {
7932            // - get days
7933            for ($i=0; $i<=7; $i++) {
7934                $cTime = strtotime("+" . $i . " days", $userTime);
7935                $schedDate = date('m/d', $cTime);
7936                $schedules[$schedDate] = array(
7937                    'day' => $weekday[date("w", $cTime)],
7938                    'd' => date('d', $cTime),
7939                    'm' => date('m', $cTime),
7940                    'y' => date('Y', $cTime)
7941                );
7942            }
7943
7944            // - arrange open_slot
7945            foreach ($result['openSlotData'] as $slot) {
7946                $shiftTime = TimezoneTable::computeTimeToUser(array(
7947                    'time' => strtotime($slot['ShiftWorkOn']['lesson_time']),
7948                    'timestamp' => $this->timeDiffSecond
7949                ));
7950                $openSlots[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7951                $openSlotsTemp[date('Y-m-d H:i:s', $shiftTime)] = $slot[0]['shiftCount'];
7952                $formattedLessonTime = date('Y-m-d H:i', $shiftTime);
7953                $lessonHour = date('H', $shiftTime);
7954                $lessonMinute = date('i', $shiftTime);
7955                $lessonDateTime = explode(' ', $formattedLessonTime);
7956                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
7957                $lessonDate = date('m/d', strtotime($lessonDate));
7958                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
7959
7960                // - state 7 : Available
7961                $state = 7;
7962
7963                //check before 5minutes
7964                if ((strtotime($slot['ShiftWorkOn']['lesson_time']) - strtotime($start_date)) <= 300) {
7965                    $state = 6;
7966                }
7967
7968                $schedules[$lessonDate]['slots'][$lessonTime] = array(
7969                    'open_avatar' => intval($slot[0]['shiftCount']),
7970                    'state' => $state,
7971                    'hour' => $lessonHour,
7972                    'minute' => $lessonMinute
7973                );
7974
7975                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($slot[0]['shiftCount']);
7976
7977                if ($corporateLimitedUser && isset($slot['TeacherRankCoin'])) {
7978                    $schedules[$lessonDate]['slots'][$lessonTime]['limited_plan_reservation'] = $slot['TeacherRankCoin']['limited_plan_reservation'];
7979                }
7980            }
7981
7982
7983
7984            // - counselor ids
7985            $avatarTeacherIds = !empty($avatarTeacherIds) ? array_values($avatarTeacherIds) : array();
7986            // - counselor reservations
7987            $userSchedules = [];
7988            $otherUserSchedules = [];
7989            foreach ($result['reservationData'] as $reservation) {
7990                //get timestamp adjusted to user timezone
7991                $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
7992                    'time' => strtotime($reservation['LessonSchedule']['lesson_time']),
7993                    'timestamp' => $this->timeDiffSecond
7994                ));
7995                $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
7996                $formattedUserLessonTime = date('Y-m-d H:i', $unixUserLessonTime);
7997
7998                $lessonHour = date('H', $unixUserLessonTime);
7999                $lessonMinute = date('i', $unixUserLessonTime);
8000                $lessonDateTime = explode(' ', $formattedUserLessonTime);
8001                $lessonDate = isset($lessonDateTime[0]) ? $lessonDateTime[0] : '';
8002                $lessonDate = date('m/d', strtotime($lessonDate));
8003                $lessonTime = isset($lessonDateTime[1]) ? $lessonDateTime[1] : '';
8004                $lsDateTime = date('Y-m-d H:i', strtotime($reservation['LessonSchedule']['lesson_time']));
8005
8006                $tempSchedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = $openSlotsTemp[$timeIndex]--;
8007
8008                // - if another user reservation
8009                if ($reservation['LessonSchedule']['user_id'] != $user_id) {
8010                    $otherUserSchedules[$lessonDate][$lessonTime] = true;
8011                }
8012
8013                // - if my reservation
8014                if ($reservation['LessonSchedule']['user_id'] == $user_id) {
8015                    $userSchedules[$lessonDate][] = $lessonTime;
8016                    if (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && !empty($openSlots[$timeIndex])) {
8017                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8018                        //get teacher details for other reservation
8019                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8020                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8021                        $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $teacherData;
8022                    } elseif (!in_array($reservation['LessonSchedule']['teacher_id'], $avatarTeacherIds) && empty($openslot[$timeIndex])) {
8023                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 3;
8024                    } else {
8025                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8026                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8027                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8028
8029                        $teacherData = $this->LessonSchedule->getReservationData($lsDateTime, $user_id, $this->localizeDir);
8030                        $teacherData['icon_color'] = $this->LessonSchedule->getIconColor($teacherData, $lsDateTime);
8031                        $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $teacherData;
8032                    }
8033
8034                    $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] = true;
8035                    $schedules[$lessonDate]['slots'][$lessonTime]['teacher_id'] = $reservation['LessonSchedule']['teacher_id'];
8036
8037                // - if not my reservations
8038                } elseif ((isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] != 1)) {
8039                    $openSlots[$timeIndex]--;
8040
8041                    if( isset($reservation['ShiftWorkOn']['hide_flg']) && $reservation['ShiftWorkOn']['hide_flg'] ) {
8042                        $openSlots[$timeIndex]++;
8043                    }
8044                    
8045                    # to prevent the schedule of the current user being overriden by other users schedules
8046                    if (isset($schedules[$lessonDate]['slots'][$lessonTime]['state']) && isset($schedules[$lessonDate]['slots'][$lessonTime]['is_reserve']) && $schedules[$lessonDate]['slots'][$lessonTime]['is_reserve'] ) {
8047                        continue;
8048                    }
8049
8050                    if (
8051                        (isset($disabledSchedule['disableAll']) && $disabledSchedule['disableAll'])
8052                        || (!empty($disabledSchedule['disabledDays']) && in_array(date('Y-m-d', $unixUserLessonTime), $disabledSchedule['disabledDays']))
8053                        && (!empty($openSlots[$timeIndex]) && $schedules[$formattedLessonTime]['state'] >= 5)
8054                    ) {
8055                        $openSlots[$timeIndex]--;
8056                        // - state 5 : can't reserve because of reservation limit
8057                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8058                            'state' => 5,
8059                            'hour' => $lessonHour,
8060                            'minute' => $lessonMinute,
8061                            'open_avatar' => intval($openSlots[$timeIndex])
8062                        );
8063
8064                    } elseif (!empty($openSlots[$timeIndex]) && $schedules[$lessonDate]['slots'][$lessonTime]['state'] >= 4) {
8065                        // - state 7 : Available
8066                        $schedules[$lessonDate]['slots'][$lessonTime] = array(
8067                            'state' => 7,
8068                            'hour' => $lessonHour,
8069                            'minute' => $lessonMinute,
8070                            'open_avatar' => intval($openSlots[$timeIndex])
8071                        );
8072                    } elseif (
8073                        isset($openSlots[$timeIndex])
8074                        && $openSlots[$timeIndex] <= 0
8075                        && (
8076                            isset($schedules[$formattedLessonTime]['state'])
8077                            && $schedules[$formattedLessonTime]['state'] >= 4
8078                            || empty($schedules[$formattedLessonTime]['state'])
8079                        )
8080                    ) {
8081                        $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 4;
8082                        $schedules[$lessonDate]['slots'][$lessonTime]['hour'] = $lessonHour;
8083                        $schedules[$lessonDate]['slots'][$lessonTime]['minute'] = $lessonMinute;
8084                        $schedules[$lessonDate]['slots'][$lessonTime]['open_avatar'] = intval($openSlots[$timeIndex]);
8085                    }
8086                }
8087            }
8088
8089            // User priority, override display schedules state
8090            foreach ($userSchedules as $lesson_date => $slots) {
8091                foreach ($slots as $lesson_time) {
8092                    // Override state when slot reserved by other
8093                    if(!empty($state = $schedules[$lesson_date]['slots'][$lesson_time]['state']) && $state === 2
8094                        && !empty($otherUserSchedules[$lesson_date][$lesson_time])) {
8095                        $schedules[$lesson_date]['slots'][$lesson_time]['state'] = 3;
8096                    }
8097                    $schedules[$lesson_date]['slots'][$lesson_time]['open_avatar'] = $tempSchedules[$lesson_date]['slots'][$lesson_time]['open_avatar'];
8098                }
8099
8100            }
8101
8102            $resData = $this->LessonSchedule->getHiddenReservation([
8103                'user_id' => $user_id
8104            ]);
8105
8106            if ($resData) {
8107                foreach ($resData as $key => $row) {
8108                    //get timestamp adjusted to user timezone
8109                    $unixUserLessonTime = TimezoneTable::computeTimeToUser(array(
8110                        'time' => strtotime($key),
8111                        'timestamp' => $this->timeDiffSecond
8112                    ));
8113                    $timeIndex = date('Y-m-d H:i:s', $unixUserLessonTime);
8114                    $lessonDate = date('m/d', $unixUserLessonTime);
8115                    $lessonTime = date('H:i', $unixUserLessonTime);
8116
8117                    if (
8118                        !empty($openSlots[$timeIndex]) && 
8119                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['teacherData']) &&
8120                        !isset($schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'])
8121                    ) {
8122
8123                        $lessonRequestSlotData = $this->LessonSchedule->getReservationData($key, $user_id, $this->localizeDir);
8124                        if (!empty($lessonRequestSlotData)) {
8125                            $lessonRequestSlotData['icon_color']  = $this->LessonSchedule->getIconColor($lessonRequestSlotData, $key);
8126
8127                            if (in_array($lessonRequestSlotData['teacher_id'], $avatarTeacherIds) && $lessonRequestSlotData['reservation_status'] == Configure::read('lesson_schedule.status.on_reserve')) {
8128                                $schedules[$lessonDate]['slots'][$lessonTime]['ownTeacherData'] = $lessonRequestSlotData;
8129                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 1;
8130                            } else {
8131                                $schedules[$lessonDate]['slots'][$lessonTime]['teacherData'] = $lessonRequestSlotData;
8132                                $schedules[$lessonDate]['slots'][$lessonTime]['state'] = 2;
8133                            }
8134                        }
8135                    }
8136                }
8137            } 
8138
8139            if ($ifForCancellation) {
8140                $this->autoRender = false;
8141                return json_encode($schedules);
8142            }
8143            
8144            // NJ-33414
8145            $this->UsersDetail->openDBReplica();
8146            $fetchUsersDetail = $this->UsersDetail->find('first', array(
8147                'fields' => array(
8148                    'lesson_request_flg'
8149                ),
8150                'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
8151                'recursive' => -1
8152            ));
8153            $this->UsersDetail->closeDBReplica();
8154            
8155            $times = array();
8156            $utcMin = explode(':', $this->utcOffset);
8157            if ($utcMin[1] == "45") {
8158                for ($i=0; $i<=23; $i++) {
8159                    $times[] = sprintf("%02d",$i) . ':15';
8160                    $times[] = sprintf("%02d",$i) . ':45';
8161                }
8162            } else {
8163                for ($i=0; $i<=23; $i++) {
8164                    $times[] = sprintf("%02d",$i) . ':00';
8165                    $times[] = sprintf("%02d",$i) . ':30';
8166                }
8167            }
8168            $this->set('times', $times);
8169            $this->set('teacherId', $teacherId);
8170            $this->set('schedules', $schedules);
8171            $this->set('campaignPeriod', $campaignPeriod);
8172        }
8173    }
8174
8175    /**
8176     * @api {post} /user/waiting/counselingLimit counselingLimit()
8177     * @apiName counselingLimit
8178     * @apiGroup Waiting
8179     * @apiDescription Checks the reservation and cancellation limits for counseling sessions for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8180     *
8181     * @apiBody {String} action The action to perform (add or cancel).
8182     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8183     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8184     * 
8185     * @apiSuccess {String} status The status of the request (OK or NG).
8186     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds counselor reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8187     * @apiSuccess {Object} lastDetails The last counseling details.
8188     * @apiSuccess {Number} lastDetails.id The ID of the last counseling session.
8189     * @apiSuccess {String} lastDetails.lesson_time The time of the last counseling session.
8190     * @apiSuccess {Number} lastDetails.teacher_id The ID of the teacher for the last counseling session.
8191     * @apiSuccess {Number} lastDetails.user_id The ID of the user for the last counseling session.
8192     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8193     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8194     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8195     * @apiSuccess {Boolean} isExpired Indicates whether the user's coin has expired.
8196     * 
8197     * @apiSuccessExample {json} Success-Response:
8198     *     {
8199     *         "status": "OK",
8200     *         "content": 0,
8201     *         "lastDetails": {
8202     *             "id": 123456,
8203     *             "lesson_time": "2023-12-01 12:00:00",
8204     *             "teacher_id": 123,
8205     *             "user_id": 123
8206     *         },
8207     *         "cancelCount": 1,
8208     *         "displayNotice": 0,
8209     *         "nextChargeDate": "2023年12月01日",
8210     *         "isExpired": false
8211     *     }
8212     *
8213     * @apiError {String} status The status of the request (NG).
8214     * @apiError {Number} content The content of the response (0: No issues).
8215     * @apiError {Number} cancelCount The count of cancellations by the user.
8216     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8217     *
8218     * @apiErrorExample {json} Error-Response:
8219     *     {
8220     *         "status": "NG",
8221     *         "content": 0,
8222     *         "cancelCount": 0,
8223     *         "displayNotice": 0
8224     *     }
8225     * 
8226     * @apiSampleRequest off
8227     */
8228    public function counselingLimit() {
8229        $this->autoRender = false;
8230        if ($this->request->is('ajax')) {
8231
8232            $userCancelledReservation = 0;
8233            $userId = $this->Auth->user('id');
8234            $action = $this->request->data['action'];
8235            $content = 0;
8236            if ($action == 'add') {
8237
8238                if (empty($this->request->data['lessonDate'])) {
8239                    return json_encode(array(
8240                        'status' => 'NG',
8241                        'content' => 0
8242                    ));
8243                }
8244
8245                // if complimentary user plan
8246                $user = $this->sharedUserData['User'];
8247                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8248                    $this->loadModel('ComplimentaryCode');
8249                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8250                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8251                        // set beyond available days to true
8252                        return json_encode(array('status' => 'OK', 'content' => 5));
8253                    }
8254                }
8255
8256                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8257
8258                // NC-7361 - corporate light
8259                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8260                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8261                        return json_encode(array('status' => 'OK', 'content' => 6));
8262                    }
8263                }
8264
8265                // - get total reservation
8266                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8267
8268                // - check if total reservation exceeds limit
8269                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8270                    $content = 2;
8271                } else {
8272                    // - show caution flag
8273                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8274                        'userId' => $userId,
8275                        'timestamp' => $this->timeDiffSecond
8276                    ));
8277
8278                    // - check reservation limit 4reservations/day
8279                    $totalReservationCounselor = $this->LessonSchedule->countUserReservationForTeacherCounselor(array(
8280                        'userId' => $userId,
8281                        'lessonDate' => $this->request->data['lessonDate'],
8282                        'timeDiffSecond' => $this->timeDiffSecond
8283                    ));
8284
8285                    // - check counselor reservations per day limit
8286                    if ($totalReservationCounselor >= 4) {
8287                        $content = 3;
8288
8289                    // - check caution flag and not yet over 20 max limit total reservation
8290                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8291                        $content = 1;
8292                    }
8293                }
8294
8295            } else {
8296                // - count total cancellations
8297                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8298                if ($userCancelledReservation >= 3) {
8299                    $content = 4;
8300                }
8301
8302                // cancel in time not allowed
8303                if(!empty($this->request->data['lessonTime']) && !$content){
8304
8305                    // if time >= lesson time(server time)
8306                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8307                        $content = 7;
8308                    }
8309                }
8310            }
8311            // get user counseling attended flag status
8312            $userData = $this->User->getUserData(
8313                array('User.id' => $userId),
8314                array(
8315                    'User.counseling_attended_flg',
8316                    'User.next_charge_date'
8317                ),
8318                'first'
8319            );
8320
8321            $nextChargeDate = "";
8322            if (isset($userData['User']['next_charge_date'])) {
8323                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8324                    'time' => strtotime($userData['User']['next_charge_date']),
8325                    'timestamp' => $this->timeDiffSecond
8326                ));
8327                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8328            }
8329            //This will be get last records for counselor details
8330            $getLastDetails = $this->Counseling->getLastCounselingById($userId);
8331
8332            $params23 = array(
8333                'user_id' => $userId,
8334                'lesson_time' =>  $this->request->data['lessonTime']
8335            );
8336            $lsId = $this->LessonSchedule->counselorCheckExpiredCoin($params23);
8337
8338            // NC-8428 - check if user has user point history record
8339            $_lsId = isset($lsId['LessonSchedule']['id']) ? $lsId['LessonSchedule']['id'] : null;
8340            $pointParam = array(
8341                'log_id' => $_lsId,
8342                'user_id' => $userId,
8343                'kbn_type' => 2, // coin  use
8344                'expiration_flg' => 2,
8345                'payment_plan_id' => isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null
8346            );
8347            $isExpired = ClassRegistry::init('UsersPointHistory')->checkCoinExpiration($pointParam);
8348
8349            return json_encode(array(
8350                'status' => 'OK',
8351                'content' => $content,
8352                'lastDetails' => $getLastDetails,
8353                'cancelCount' => $userCancelledReservation,
8354                'displayNotice' => (isset($userData['User']['counseling_attended_flg'])) ? $userData['User']['counseling_attended_flg'] : 0,
8355                'nextChargeDate' => $nextChargeDate,
8356                'isExpired' => $isExpired,
8357            ));
8358        } else {
8359            return json_encode(array(
8360                'status' => 'NG',
8361                'content' => 0,
8362                'cancelCount' => 0,
8363                'displayNotice' => 0
8364            ));
8365        }
8366    }
8367
8368    /**
8369     * @api {post} /user/waiting/avatarLimit avatarLimit()
8370     * @apiName avatarLimit
8371     * @apiGroup Waiting
8372     * @apiDescription Checks the reservation and cancellation limits for avatar lessons for the authenticated user in Native Camp. It returns the status and any relevant messages or limits.
8373     *
8374     * @apiBody {String} action The action to perform (add or cancel).
8375     * @apiBody {String} teacher_avatar The ID of the avatar teacher.
8376     * @apiBody {String} [lessonDate] The date of the lesson (required for add action).
8377     * @apiBody {String} [lessonTime] The time of the lesson (required for cancel action).
8378     * 
8379     * @apiSuccess {String} status The status of the request (OK or NG).
8380     * @apiSuccess {Number} content The content of the response (0: No issues, 1: Caution flag, 2: Exceeds total reservation limit, 3: Exceeds avatar reservations per day limit, 4: Exceeds cancellation limit, 5: Beyond available days for complimentary plan, 6: Exceeds corporate light lesson limit, 7: Cancel in time not allowed).
8381     * @apiSuccess {Number} cancelCount The count of cancellations by the user.
8382     * @apiSuccess {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8383     * @apiSuccess {String} nextChargeDate The next charge date for the user.
8384     *
8385     * @apiSuccessExample {json} Success-Response:
8386     *     {
8387     *         "status": "OK",
8388     *         "content": 0,
8389     *         "cancelCount": 1,
8390     *         "displayNotice": 0,
8391     *         "nextChargeDate": "2023年12月01日"
8392     *     }
8393     *
8394     * @apiError {String} status The status of the request (NG).
8395     * @apiError {Number} content The content of the response (0: No issues).
8396     * @apiError {Number} cancelCount The count of cancellations by the user.
8397     * @apiError {Number} displayNotice Indicates whether to display a notice (0: No, 1: Yes).
8398     *
8399     * @apiErrorExample {json} Error-Response:
8400     *     {
8401     *         "status": "NG",
8402     *         "content": 0,
8403     *         "cancelCount": 0,
8404     *         "displayNotice": 0
8405     *     }
8406     * 
8407     * @apiSampleRequest off
8408     */
8409    public function avatarLimit() {
8410        $this->autoRender = false;
8411        if ($this->request->is('ajax')) {
8412
8413            $userCancelledReservation = 0;
8414            $userId = $this->Auth->user('id');
8415            $action = $this->request->data['action'];
8416            $teacherAvatarId = $this->request->data['teacher_avatar'];
8417            $content = 0;
8418            if ($action == 'add') {
8419
8420                if (empty($this->request->data['lessonDate'])) {
8421                    return json_encode(array(
8422                        'status' => 'NG',
8423                        'content' => 0
8424                    ));
8425                }
8426
8427                // if complimentary user plan
8428                $user = $this->sharedUserData['User'];
8429                if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
8430                    $this->loadModel('ComplimentaryCode');
8431                    $user['lessonTime'] = date('Y-m-d', strtotime($this->request->data['lessonDate']));
8432                    if (!$result = $this->ComplimentaryCode->validateUserComplimentaryPlan($user)) {
8433                        // set beyond available days to true
8434                        return json_encode(array('status' => 'OK', 'content' => 5));
8435                    }
8436                }
8437
8438                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
8439
8440                // NC-7361 - corporate light
8441                if (isset($corporateType) && $corporateType == Configure::read('corporate_type.light')) {
8442                    if (ClassRegistry::init('Corporate')->corpLightLessonMaxLimit(array("user_id" => $userId))) {
8443                        return json_encode(array('status' => 'OK', 'content' => 6));
8444                    }
8445                }
8446
8447                // - get total reservation
8448                $totalReservation = $this->LessonSchedule->countUserTotalReservation(array('userId' => $userId));
8449
8450                // - check if total reservation exceeds limit
8451                if ($totalReservation >= Configure::read("maximum_number_of_total_reservation")) {
8452                    $content = 2;
8453                } else {
8454                    // - show caution flag
8455                    $reservationCautionFlag = $this->LessonSchedule->reservationCautionFlag(array(
8456                        'userId' => $userId,
8457                        'timestamp' => $this->timeDiffSecond
8458                    ));
8459
8460                    // - check reservation limit 4reservations/day
8461                    $totalReservationAvatar = $this->LessonSchedule->countUserReservationForTeacherAvatar(array(
8462                        'avatar_id' => $teacherAvatarId,
8463                        'userId' => $userId,
8464                        'lessonDate' => $this->request->data['lessonDate'],
8465                        'timeDiffSecond' => $this->timeDiffSecond
8466                    ));
8467
8468                    // - check avatar reservations per day limit
8469                    if ($totalReservationAvatar >= 4) {
8470                        $content = 3;
8471
8472                    // - check caution flag and not yet over 20 max limit total reservation
8473                    } elseif ($reservationCautionFlag && $totalReservation < 20) {
8474                        $content = 1;
8475                    }
8476                }
8477
8478            } else {
8479                // - count total cancellations
8480                $userCancelledReservation = $this->LessonScheduleCancel->countCancelledReservation(array('userId' => $userId));
8481                if ($userCancelledReservation >= 3) {
8482                    $content = 4;
8483                }
8484
8485                // cancel in time not allowed
8486                if(!empty($this->request->data['lessonTime']) && !$content){
8487
8488                    // if time >= lesson time(server time)
8489                    if(strtotime('now') >= strtotime($this->request->data['lessonTime'])){
8490                        $content = 7;
8491                    }
8492                }
8493            }
8494            // get user
8495            $userData = $this->User->getUserData(
8496                array('User.id' => $userId),
8497                array(
8498                    'User.next_charge_date'
8499                ),
8500                'first'
8501            );
8502
8503            $nextChargeDate = "";
8504            if (isset($userData['User']['next_charge_date'])) {
8505                $chargeDateJP = TimezoneTable::computeTimeToUser(array(
8506                    'time' => strtotime($userData['User']['next_charge_date']),
8507                    'timestamp' => $this->timeDiffSecond
8508                ));
8509                $nextChargeDate = date('Y', $chargeDateJP) . "年" . date('m', $chargeDateJP) . "月" . date('d', $chargeDateJP) . "日";
8510            }
8511
8512            return json_encode(array(
8513                'status' => 'OK',
8514                'content' => $content,
8515                'cancelCount' => $userCancelledReservation,
8516                'displayNotice' => 0,
8517                'nextChargeDate' => $nextChargeDate
8518            ));
8519        } else {
8520            return json_encode(array(
8521                'status' => 'NG',
8522                'content' => 0,
8523                'cancelCount' => 0,
8524                'displayNotice' => 0
8525            ));
8526        }
8527    }
8528
8529    /**
8530     * @api {post} /user/waiting/checkCounselingReservationNow checkCounselingReservationNow()
8531     * @apiName checkCounselingReservationNow
8532     * @apiGroup Waiting
8533     * @apiDescription Checks if the user has a reserved counseling session at the current time. It returns the status of the reservation and the teacher's information if available.
8534     *
8535     * @apiBody {String} userId The ID of the user.
8536     * 
8537     * @apiSuccess {String} status The status of the request (OK or NG).
8538     * @apiSuccess {Number} [state] The state of the counseling reservation (1: No reserved counseling, 2: Reserved counseling and teacher is on standby, 3: Reserved counseling and teacher is not on standby).
8539     * @apiSuccess {String} [teacher_id] The ID of the teacher (if state is 2).
8540     * @apiSuccess {String} [chat_hash] The chat hash of the lesson (if state is 2).
8541     *
8542     * @apiSuccessExample {json} Success-Response:
8543     *     {
8544     *         "status": "OK",
8545     *         "state": 2,
8546     *         "teacher_id": "123",
8547     *         "chat_hash": "example_chat_hash"
8548     *     }
8549     *
8550     * @apiError {String} status The status of the request (NG).
8551     *
8552     * @apiErrorExample {json} Error-Response:
8553     *     {
8554     *         "status": "NG"
8555     *     }
8556     * 
8557     * @apiSampleRequest off
8558     */
8559    public function checkCounselingReservationNow() {
8560        $this->autoRender = false;
8561        $data = $this->request->data;
8562        $result = array('status' => 'OK');
8563
8564        if (empty($data['userId'])) {
8565            return json_encode(array(
8566                'status' => 'NG'
8567            ));
8568        }
8569
8570        if ($this->request->is('ajax')) {
8571            //target lesson schedule start time
8572            $minutes = date('i');
8573            if ($minutes >= 0 && $minutes < 26) {
8574                $lessonTime = date('Y-m-d H:00:00');
8575            } elseif ($minutes >= 30 && $minutes < 56) {
8576                $lessonTime = date('Y-m-d H:30:00');
8577            } else {
8578                // - [1] if user has no reserved counseling
8579                $result['state'] = 1;
8580                return json_encode($result);
8581            }
8582
8583            // - check ongoing lesson
8584            $counselingInfo = $this->LessonSchedule->find('first', array(
8585                    'fields' => array(
8586                        'LessonSchedule.id',
8587                        'LessonOnair.teacher_id',
8588                        'LessonOnair.chat_hash'
8589                    ),
8590                    'conditions' => array(
8591                        'LessonSchedule.lesson_time' => $lessonTime,
8592                        'LessonSchedule.user_id' => $data['userId']
8593                    ),
8594                    'joins' => array(
8595                        array(
8596                            'type' => 'LEFT',
8597                            'table' => 'lesson_onairs',
8598                            'alias' => 'LessonOnair',
8599                            'conditions' => array('LessonSchedule.teacher_id = LessonOnair.teacher_id AND LessonOnair.connect_flg = 1')
8600                        ),
8601                        array(
8602                            'type' => 'INNER',
8603                            'table' => 'teachers',
8604                            'alias' => 'Teacher',
8605                            'conditions' => array('Teacher.id = LessonOnair.teacher_id AND Teacher.counseling_flg = 1')
8606                        )
8607                    ),
8608                    'recursive' => -1
8609                )
8610            );
8611
8612            // - [1] if user has no reserved counseling
8613            if (empty($counselingInfo)) {
8614                $result['state'] = 1;
8615                return json_encode($result);
8616            }
8617
8618            // - [2] if user has reserved counseling and teacher is on standby
8619            if (!empty($counselingInfo['LessonOnair']['chat_hash'])) {
8620                $result['state'] = 2;
8621                $result['teacher_id'] = $counselingInfo['LessonOnair']['teacher_id'];
8622                $result['chat_hash'] = $counselingInfo['LessonOnair']['chat_hash'];
8623                return json_encode($result);
8624
8625            // - [3] if user has reserved counseling and teacher is not on standby
8626            } elseif (empty($counselingInfo['LessonOnair']['chat_hash'])) {
8627                $result['state'] = 3;
8628                return json_encode($result);
8629            } else {
8630                $result['state'] = 1;
8631                return json_encode($result);
8632            }
8633
8634        } else {
8635            return json_encode(array(
8636                'status' => 'NG'
8637            ));
8638        }
8639    }
8640
8641
8642    //Retrieves the details of a specific teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
8643    public function spDetail($teacherId) {
8644        if (!intval($teacherId)) {
8645            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8646        }
8647
8648        // NJ-10759: redirect to mypage if teacher detail sp is counseling and access from teacher mobapp
8649        // redirect if counseling teacher
8650        $counselorParams = array(
8651            'type' => 'count',
8652            'args' => array(
8653                'conditions' => array(
8654                    'id' => $teacherId,
8655                    'counseling_flg' => 1
8656                ),
8657                'recursive' => -1
8658            )
8659        );
8660
8661
8662        // - NC-3802: redirect to mypage if counselor teacher
8663        if ($this->Teacher->getTeachers($counselorParams)) {
8664            return $this->redirect(myTools::getUrl() . '/user/mypage');
8665        }
8666
8667        //fetch teacher data
8668        $data = $this->Teacher->findById($teacherId);
8669
8670        //no teacher data
8671        if (!$data) {
8672            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
8673        }
8674
8675        // //check company ip and if the teacher is stealth on redirect to teacher list
8676        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
8677        //     return $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
8678        // }
8679
8680        //redirect if withdrawn teacher
8681        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1) {
8682            return $this->redirect(myTools::geturl() . '/waiting');
8683        }
8684
8685        if(in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
8686            return $this->redirect('/waiting');
8687        }
8688
8689        // - check if blocked student
8690        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
8691            return $this->redirect('/waiting');
8692        }
8693
8694        // - NC-7031: redirect avatar
8695        $avatarData = $this->isAvatar($teacherId);
8696
8697        if ($avatarData) {
8698            $getAId = $avatarData;
8699            return $this->redirect('/avatar_detail/'.$getAId);
8700        }
8701
8702        //lesson onair
8703        $onair1 = $this->LessonOnair->find('first', array(
8704            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
8705            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
8706        ));
8707
8708        //teacher_status if login or break
8709        $teacherStatus1 = $this->TeacherStatus->find('first', array(
8710            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
8711            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
8712            );
8713        // get counrty details
8714        $teacherCountryDetails = $this->CountryCode->find('first', array(
8715            'fields' => array('country_name', 'nationality', 'code'),
8716            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
8717            );
8718
8719        //get own reviews
8720        $selfReviews = array();
8721        $selfLessonCount = 0;
8722        $selfLessonNow = 0;
8723        $selfReservation = 0;
8724        $daysPast = 0;
8725        $userId = $this->Auth->user('id');
8726        $this->set('userId', $userId);
8727        if ($userId) {
8728            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
8729            $selfReviews = $this->getUserReviews($userId, $teacherId);
8730            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
8731            $selfLessonNow = $userLessonDetail['lessonCount'];
8732            $selfReservation = $userLessonDetail['reserveCount'];
8733            $selfLessonCount = $selfLessonNow + $selfReservation;
8734            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
8735        }
8736
8737        if (!empty($onair1)) {
8738            $onair = new LessonOnairTable($onair1['LessonOnair']);
8739        } elseif (!empty($teacherStatus1)) {
8740            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
8741        } else {
8742            $onair = 0;
8743        }
8744
8745        $rateBreakdown = null;
8746        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
8747        if ($rating) {
8748            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
8749            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
8750        }
8751
8752        $this->set('onair', $onair);
8753        $this->set('teacher_id', $teacherId);
8754
8755        $teacher = new TeacherTable($data['Teacher']);
8756        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
8757        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
8758        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
8759        $this->set('teacher', $teacher);
8760
8761        # get weekly rating
8762        $get_weekly_rating = $this->UsersClassEvaluation->getRatings($teacherId,true);
8763        if ($get_weekly_rating['TeacherWeeklyRating']['averageRate']) {
8764            $get_weekly_rating['TeacherWeeklyRating']['ratings'] = $get_weekly_rating['TeacherWeeklyRating']['averageRate'];
8765        }
8766
8767        //number of lesson
8768        $lessonCount = (int)$teacher->lesson_count;
8769
8770        // Translate and save translated data
8771        $globalTranslate = TeacherTable::translate(array(
8772            'id' => $teacher->id,
8773            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
8774            'controller' => static::class
8775        ));
8776        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
8777        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
8778        $this->set('message', $translatedMessageTranslation);
8779        $this->set('intro', $translatedThirdppTranslation);
8780
8781        // NJ-32759
8782        $userLang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('english_language_id');
8783        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
8784        $getCRData = $this->Teacher->getCountryResidenceData($teacherId, $userLang, 'first', $languageIds);
8785        $residenceData = $this->getResidenceData($getCRData);
8786        $this->set('residenceData',$residenceData);
8787        $this->set('residenceFlg',$residenceData['countryFlag']);
8788
8789        // get teacher strength feature items
8790        $strengthItemsParams = array(
8791            'teacherId' => $teacherId,
8792            'type' => 0,
8793            'langId' => $this->CountryCode->getUserLanguageId($this->localizeDir),
8794            'limit' => 3
8795        );
8796        $showRating = $teacher->getReviewOption($teacher->rank_coin_id);
8797        $this->set('showRating', $showRating);
8798        $strengthItems = $this->TeacherFeatureRating->getFeatureRatingItems($strengthItemsParams);
8799        $this->set('strengthItems', $strengthItems);
8800        
8801        // - prepare head text
8802        $headTextWD = $pageTitleWD = $teacher->name;
8803        $metaDescWD = "";
8804        if ($this->localizeDir == Configure::read('default.user_language')) {
8805            $headTextWD .= '('.$teacher->jp_name.')';
8806            $pageTitleWD .=  '('.$teacher->jp_name.')';
8807            //$metaDescWD .= '('.$teacher->jp_name.')';
8808        }
8809
8810        //find the selfintro 
8811        $TeacherTable = new TeacherTable($teacher);
8812        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
8813        $_userSelfIntro = strip_tags($_userSelfIntro); 
8814
8815        //prepare meta image 
8816        $_teacherImgUrl = $teacher->getImageUrl();
8817
8818        //check if teacher has no image 
8819        if (empty($teacher->image_url) || !$teacher->image_url) {
8820            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
8821            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
8822        }
8823
8824        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
8825        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
8826        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
8827        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
8828
8829
8830        // NJ-3786 textbook teacher recommendation
8831        $curDate = date('Y-m-d');
8832        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
8833        $txtTeacherRecommendlimit = 10;
8834        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
8835        $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
8836        $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
8837
8838        if( $userId ) {
8839            $teacherObj = new TeacherTable($data['Teacher']);
8840            $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 'user_id' => $userId ) );
8841            $textbookCategoryId = $lastBookUsedData['category_id'];
8842            $textbookBadge = $lastBookUsedData['textbook_badge'];
8843            $paramsArr = array(
8844                'user_id' => $userId,
8845                'begin_date' => $beginDate,
8846                'end_date' => $endDate,
8847                'textbook_category' => $textbookCategoryId,
8848                'textbook_badge' => $textbookBadge,
8849                'limit' => $txtTeacherRecommendlimit,
8850                'user_data' => $userData,
8851                'exclude_teacher_id' => $teacherId
8852            );
8853
8854            $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
8855            if( $teacherTextbookStatData ) {
8856                $dataList = $this->arrangeTeacherRecommendList( array( 
8857                        'user_id' => $userId,
8858                        'data' => $teacherTextbookStatData,
8859                        'category_id' => $textbookCategoryId,
8860                        'user_data' => $userData
8861                    ) 
8862                );
8863                $this->set('textbookTeacherData', $dataList);
8864            }
8865
8866            // - user callan unli option flg
8867            $callan_option = isset($this->sharedUserData['User']['callan_option']) ? $this->sharedUserData['User']['callan_option'] : 0;
8868
8869            // - user native unli option flg
8870            $native_option = isset($this->sharedUserData['User']['native_option']) ? $this->sharedUserData['User']['native_option'] : 0;
8871
8872            $can_use_callan_option = 0;
8873            if($callan_option || $native_option) {
8874                $can_use_callan_option = 1;
8875            }
8876
8877            $this->set('can_use_callan_option', $can_use_callan_option);
8878
8879            // - teacher callan unli option flg
8880            $unlimited_option_flag = $this->HomeBasedRankBasicAmount->getUnlimitedOptionFlg($teacherObj->current_rank_id);
8881            $callan_option_teacher_flg = (isset($unlimited_option_flag['callan_unlimited_option_flg']) && $unlimited_option_flag['callan_unlimited_option_flg']) ? $unlimited_option_flag['callan_unlimited_option_flg'] : 0; 
8882            $this->set('callan_option_teacher_flg', $callan_option_teacher_flg);
8883            
8884            // - check if has callan badge
8885            $teacher_callan_badge = ClassRegistry::init('TeacherBadge')->checkCallanBadges(array('teacher_id' => $teacherId));
8886            $this->set('teacher_callan_badge', $teacher_callan_badge);
8887        }
8888
8889        // - set page meta information
8890        $this->set('headtext', $headTextWD);
8891        $this->set('title_for_layout', $pageTitleWD);
8892        $this->set('meta_description', $metaDescWD);
8893        $this->set('lessonCount', $lessonCount);
8894        $this->set('country', $country);
8895        $this->set('rateBreakdown', $rateBreakdown);
8896        $this->set('selfReviews', $selfReviews);
8897        $this->set('selfLessonCount', $selfLessonCount);
8898        $this->set('daysPast', $daysPast);
8899        $this->set('meta_teacher_img',$_teacherImgUrl);
8900
8901        # get studydapuri textbooks
8902        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
8903        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
8904            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
8905            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
8906        } elseif ($this->isStudySapuriTosUser) {
8907            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
8908        } else {
8909            $exCat = Configure::read('all_sapuri_textbook_category_types');
8910            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
8911        }
8912
8913        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
8914
8915        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
8916        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
8917        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
8918        $lessonHistories = $this->getLessonHistory(true, $teacherId);
8919        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
8920
8921        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
8922        $coinParams =  array(
8923            'current_rank_id' => $teacherCurrentRankId,
8924            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
8925            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
8926            'student_native_option' => $userData->native_option,
8927            'home_flg' => $teacher->home_flg,
8928            'counseling_flg' => $teacher->counseling_flg,
8929            'avatar_parent_flg' => $teacher->avatar_parent_flg,
8930            'avatar_flg' => $teacher->avatar_flg,
8931            'native_speaker_flg' => $teacher->native_speaker_flg
8932        );
8933
8934        // get teacher coin settings
8935        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
8936        $teacherCoinData = [];
8937        if($teacherReserveCoin){
8938            // set teacher reservation coin
8939            $teacherCoinData = [
8940                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
8941                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
8942                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
8943                'reserve_coin_with_op' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
8944                'displayNativeOptionAmountFlg' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
8945                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
8946                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
8947            ];
8948            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
8949            $teacherCoinData['callan_coin'] = (int) $callanCoin;
8950            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
8951
8952            $sapuriCoin = 0;
8953            if ($this->isStudySapuriUser) {
8954                $teacherParams = array(
8955                    'teacher_id' => $teacher->id,
8956                    'current_rank_id' => $teacherCurrentRankId
8957                );
8958                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
8959            }
8960
8961        }
8962
8963        $OS = myTools::getOSFromUA($_SERVER['HTTP_USER_AGENT'], TRUE);
8964
8965        // NJ-20069 - feature tag lists
8966        $feature_tags_list = [
8967            "new" => "新人講師",
8968            "best_free_talk" => "フリートークが得意",
8969            "good_in_teaching_textbook" => "教材レッスンが得意",
8970            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
8971            "have_many_beginner_students" => "初級者向き",
8972            "suitable_for_children" => "キッズ向き",
8973            "suitable_for_senior" => "シニア向き",
8974            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
8975            "good_for_first_timer" => "体験レッスン向き",
8976            "pronunciation" => "発音"
8977        ];
8978        $data = $this->User->findById($userId);
8979
8980        // NJ-17264
8981        $titleThresholdData = [];
8982
8983        $this->TitleThresholdTeacher->openDBReplica();
8984        $titleThresholdData = $this->TitleThresholdTeacher->find('first', [
8985            'fields'=>'TitleThresholdTeacher.title_type',
8986            'conditions' => array(
8987                'TitleThresholdTeacher.teacher_id' => $teacherId,
8988                'TitleThresholdTeacher.type = 1'
8989            ),
8990            'recursive' => -1
8991        ]);
8992        $this->TitleThresholdTeacher->closeDBReplica();
8993        // NJ-17264
8994
8995        $this->set('user',$data);
8996        $this->set('userOS', $OS);
8997        $this->set('localizeDir', $this->localizeDir);
8998        $this->set('teacherCoinData', $teacherCoinData);
8999        $this->set('lessonHistories', $lessonHistories);
9000        $this->set('teacherRates', $reserveAndCancel);
9001        $this->set('teacherOccupation', $teacherOccupation);
9002        $this->set('series', $return['series']);
9003        $this->set('feature', $return['feature']);
9004        $this->set('historyMonth', $historyMonth);
9005        $this->set('historyYear', $historyYear);
9006        $this->set('weekly_ratings', $get_weekly_rating['TeacherWeeklyRating']);
9007        $this->set('teacherId', $teacherId);
9008        $this->set('feature_tags_list', $feature_tags_list);
9009        $this->set('features', $this->teacherFeatures(true, $teacherId));
9010        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9011        $this->set('favoriteCount', $favoriteCount);
9012        $this->set('sapuriCoin', $sapuriCoin);
9013        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9014        $this->set('title_type', isset($titleThresholdData['TitleThresholdTeacher']['title_type']) ? $titleThresholdData['TitleThresholdTeacher']['title_type'] : 0);
9015
9016        $this->layout = 'mobile';
9017        $this->render('/Mobile/Teacher/detail');
9018    }
9019
9020
9021    //Retrieves the details of a specific avatar teacher for the mobile view in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9022    public function spAvatarDetail($teacherId) {
9023        if (!intval($teacherId)) {
9024            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9025        }
9026
9027        //fetch teacher data
9028        $data = $this->Teacher->findById($teacherId);
9029
9030        //no teacher data
9031        if (!$data) {
9032            return $this->redirect(myTools::getUrl() . '/user/mobapp/retrypage');
9033        }
9034
9035        // //check company ip and if the teacher is stealth on redirect to teacher list
9036        // if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR']) && $data['Teacher']['stealth_flg']) {
9037        //     $this->redirect(array('controller' => 'SpTeacher', 'action' => 'index'));
9038        // }
9039
9040        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9041            return $this->redirect('/waiting');
9042        }
9043
9044        //lesson onair
9045        $onair1 = $this->LessonOnair->find('first', array(
9046            'fields' => array('LessonOnair.status', 'LessonOnair.connect_flg'),
9047            'conditions' => array('LessonOnair.teacher_id' => $data['Teacher']['id'])
9048            ));
9049
9050        //number of reservation
9051
9052        //teacher_status if login or break
9053        $teacherStatus1 = $this->TeacherStatus->find('first', array(
9054            'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1'),
9055            'conditions' => array('TeacherStatus.teacher_id' => $data['Teacher']['id']))
9056            );
9057        // get counrty details
9058        $teacherCountryDetails = $this->CountryCode->find('first', array(
9059            'fields' => array('country_name', 'nationality', 'code'),
9060            'conditions' => array('CountryCode.id' => $data['Teacher']['homeland2']))
9061            );
9062
9063        //get own reviews
9064        $selfReviews = array();
9065        $selfLessonCount = 0;
9066        $selfLessonNow = 0;
9067        $selfReservation = 0;
9068        $daysPast = 0;
9069        $userId = $this->Auth->user('id');
9070        if ($userId) {
9071            $this->set('user_lang',  $this->sharedUserData['User']['native_language2']);
9072            $selfReviews = $this->getUserReviews($userId, $teacherId);
9073            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9074            $selfLessonNow = $userLessonDetail['lessonCount'];
9075            $selfReservation = $userLessonDetail['reserveCount'];
9076            $selfLessonCount = $selfLessonNow + $selfReservation;
9077            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9078        }
9079
9080        if (!empty($onair1)) {
9081            $onair = new LessonOnairTable($onair1['LessonOnair']);
9082        } elseif (!empty($teacherStatus1)) {
9083            $onair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9084        } else {
9085            $onair = 0;
9086        }
9087
9088
9089        $this->set('onair', $onair);
9090        $this->set('teacher_id', $teacherId);
9091
9092        $teacher = new TeacherTable($data['Teacher']);
9093        $country = new TeacherTable($teacherCountryDetails['CountryCode']);
9094        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9095        $meta_desc = preg_replace('/\s+/', ' ', trim($teacher->getMetaMobile()));
9096        $this->set('teacher', $teacher);
9097
9098        # get weekly rating
9099        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
9100        //number of lesson
9101        $lessonCount = (int)$teacher->lesson_count;
9102
9103        //number of lesson for all child accounts
9104        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9105
9106        // Translate and save translated data
9107        $globalTranslate = TeacherTable::translate(array(
9108            'id' => $teacher->id,
9109            'lang'=> isset($this->localizeDir) ? $this->localizeDir : $this->lang_iso,
9110            'controller' => static::class
9111        ));
9112        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
9113        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
9114        $this->set('message', $translatedMessageTranslation);
9115        $this->set('intro', $translatedThirdppTranslation);
9116
9117        // - prepare head text
9118        $headTextWD = $pageTitleWD  = $teacher->name;
9119        $metaDescWD = "";
9120
9121        //find the selfintro 
9122        $TeacherTable = new TeacherTable($teacher);
9123        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
9124        $_userSelfIntro = strip_tags($_userSelfIntro); 
9125
9126        if ($this->localizeDir == Configure::read('default.user_language')) {
9127            $headTextWD .= '('.$teacher->jp_name.')';
9128            $pageTitleWD .=  '('.$teacher->jp_name.')';
9129            //$metaDescWD .= '('.$teacher->jp_name.')';
9130        }
9131        $headTextWD .= '&ensp;' . __d('waiting', 'レッスン').':'.$lessonCount.__d('waiting', '回');
9132        $pageTitleWD .= '&ensp;' . sprintf(__d('waiting', 'レッスン:%s回 - 講師詳細 | オンライン英会話のネイティブキャンプ'), $lessonCount);
9133        //$metaDescWD .= '講師の紹介ページです。'.$teacher->getMetaDescription();
9134        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
9135
9136        //prepare meta image 
9137        $_teacherImgUrl = $teacher->getImageUrl();
9138
9139        //check if teacher has no image 
9140        if (empty($teacher->image_url) || !$teacher->image_url) {
9141            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9142            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9143        }
9144
9145
9146        // - set page meta information
9147        $this->set('headtext', $headTextWD);
9148        $this->set('title_for_layout', $pageTitleWD);
9149        $this->set('meta_description', $metaDescWD);
9150        $this->set('lessonCount', $lessonCount);
9151        $this->set('country', $country);
9152        //$this->set('rateBreakdown', $rateBreakdown);
9153        $this->set('selfReviews', $selfReviews);
9154        $this->set('selfLessonCount', $selfLessonCount);
9155        $this->set('daysPast', $daysPast);
9156        $this->set('meta_teacher_img',$_teacherImgUrl);
9157    
9158
9159        # get studydapuri textbooks
9160        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
9161        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
9162            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
9163            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
9164        } elseif ($this->isStudySapuriTosUser) {
9165            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
9166        } else {
9167            $exCat = Configure::read('all_sapuri_textbook_category_types');
9168            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
9169        }
9170        
9171        $return = TeacherDetailTable::teacherIntroDetails($data, $this->localizeDir,$this->Auth->loggedIn(),$conArr);
9172
9173        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9174        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9175        $lessonHistories = $this->getLessonHistory(true, $teacherId);
9176        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => array('UsersFavorite.teacher_id' => $teacherId)));
9177
9178        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacherId);
9179
9180        // get user data
9181        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9182
9183        $coinParams =  array(
9184            'current_rank_id' => $teacherCurrentRankId,
9185            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9186            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9187            'student_native_option' => $userData['native_option'],
9188            'home_flg' => $teacher->home_flg,
9189            'counseling_flg' => $teacher->counseling_flg,
9190            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9191            'avatar_flg' => $teacher->avatar_flg,
9192            'native_speaker_flg' => $teacher->native_speaker_flg
9193        );
9194
9195        // get teacher coin settings
9196        $teacherReserveCoin = $this->Teacher->getTeacherReserveCoin($coinParams);
9197        $teacherCoinData = [];
9198        if($teacherReserveCoin){
9199            // set teacher reservation coin
9200            $teacherCoinData = [
9201                'lesson_now' => (int) $teacherReserveCoin['lesson_coin'],
9202                'reserve_coin' => (int) $teacherReserveCoin['reserve_coin'],
9203                'reserve_coin_before_discount' => (int) $teacherReserveCoin['reserve_coin_before_discount'],
9204                'displayNativeOptionAmountFlg' => isset($teacherReserveCoin['display_native_option_amount_flg']) ? (int) $teacherReserveCoin['display_native_option_amount_flg'] : false,
9205                'reserve_coin_with_op' =>  isset($teacherReserveCoin['reserve_coin_with_op']) ? (int) $teacherReserveCoin['reserve_coin_with_op'] : null,
9206                'teacherCoinWithOp' => $teacherReserveCoin['reserve_coin_with_op'],
9207                'teacherCoinBeforeDiscount' => $teacherReserveCoin['reserve_coin_before_discount']
9208            ];
9209            $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoinData['reserve_coin'] / 2 : $teacherCoinData['reserve_coin'];
9210            $teacherCoinData['callan_coin'] = (int) $callanCoin;
9211
9212            $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9213
9214            $sapuriCoin = 0;
9215            if ($this->isStudySapuriUser) {
9216                $teacherParams = array(
9217                    'teacher_id' => $teacher->id,
9218                    'current_rank_id' => $teacherCurrentRankId
9219                );
9220                $sapuriCoin = $this->Teacher->getStudySapuriCoin($teacherParams);
9221            }
9222
9223        }
9224        
9225        // NJ-42412 - added feature also to spAvatarDetail (Related to NJ-20069)
9226        $feature_tags_list = [
9227            "new" => "新人講師",
9228            "best_free_talk" => "フリートークが得意",
9229            "good_in_teaching_textbook" => "教材レッスンが得意",
9230            "suitable_for_intermediate_or_advance_students" => "中/上級者向き",
9231            "have_many_beginner_students" => "初級者向き",
9232            "suitable_for_children" => "キッズ向き",
9233            "suitable_for_senior" => "シニア向き",
9234            "good_grammar_and_vocabulary" => "文法・ボキャブラリー",
9235            "good_for_first_timer" => "体験レッスン向き",
9236            "pronunciation" => "発音"
9237        ];
9238        $this->set('teacherCoinData', $teacherCoinData);
9239        $this->set('lessonHistories', $lessonHistories);
9240        $this->set('teacherRates', $reserveAndCancel);
9241        $this->set('series', $return['series']);
9242        $this->set('features', json_encode((array)$return['feature']));
9243        $this->set('historyMonth', $historyMonth);
9244        $this->set('historyYear', $historyYear);
9245        $this->set('weekly_ratings', isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0);
9246        $this->set('teacherId', $teacherId);
9247        $this->set('avatarId', $this->isAvatar($teacherId));
9248        $this->set('favoriteCount', $favoriteCount);
9249        $this->set('feature_tags_list', $feature_tags_list);
9250        $this->set('sapuriCoin', $sapuriCoin);
9251        $this->set('teacherCallanDiscount', empty($teacherCallanDiscount)? 0: $teacherCallanDiscount);
9252        $this->layout = 'mobile';
9253        $this->render('/Mobile/Teacher/avatar_detail');
9254    }
9255
9256    /**
9257     * @api {get} /user/:language/avatar_detail/:teacherId/:highLightFlag avatar_detail()
9258     * @apiName avatar_detail
9259     * @apiGroup Waiting
9260     * @apiDescription Retrieves the details of a specific avatar teacher in Native Camp. It returns various information about the teacher, including lesson history, reviews, and more.
9261     *
9262     * @apiParam {String} language The language code for the page.
9263     * @apiParam {String} teacherId The ID of the avatar teacher.
9264     * @apiParam {Boolean} [highLightFlag] Indicates whether to highlight certain elements on the page.
9265     * 
9266     * @apiSuccess {Object} teacher The teacher information.
9267     * @apiSuccess {String} teacher.id The ID of the teacher.
9268     * @apiSuccess {String} teacher.name The name of the teacher.
9269     * @apiSuccess {String} teacher.jp_name The Japanese name of the teacher.
9270     * @apiSuccess {String} teacher.image_url The URL of the teacher's image.
9271     * @apiSuccess {Object} country The country information.
9272     * @apiSuccess {String} country.country_name The name of the country.
9273     * @apiSuccess {String} country.national The nationality.
9274     * @apiSuccess {Object} timezone The timezone information.
9275     * @apiSuccess {String} timezone.timezone The timezone.
9276     * @apiSuccess {Object} tutorCategory The tutor category information.
9277     * @apiSuccess {Number} tutorCategory.coins The number of coins the teacher has.
9278     * @apiSuccess {Number} tutorCategory.limited_plan_reservation Indicates whether the teacher has a limited plan reservation (0: No, 1: Yes).
9279     * @apiSuccess {Number} timeDiff The time difference between the user's local time and the teacher's time.
9280     * @apiSuccess {Object} onair The on-air lesson information.
9281     * @apiSuccess {Number} onair.status The status of the on-air lesson.
9282     * @apiSuccess {Number} onair.connect_flg Indicates whether the teacher is connected (1: Yes, 0: No).
9283     * @apiSuccess {Number} teacherCoin The coin amount for the teacher.
9284     * @apiSuccess {Number} callanCoin The Callan coin amount for the teacher.
9285     * @apiSuccess {Number} teacherCallanDiscount The Callan discount for the teacher.
9286     * @apiSuccess {Number} lessonCount The number of lessons the teacher has conducted.
9287     * @apiSuccess {Number} historyYear The number of years the teacher has been teaching.
9288     * @apiSuccess {Number} historyMonth The number of months the teacher has been teaching.
9289     * @apiSuccess {Object} keep_memo The memo kept by the user for the teacher.
9290     * @apiSuccess {String} keep_memo.memo The memo text.
9291     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown.
9292     * @apiSuccess {Number} reserveAndCancel.reserve The number of reservations.
9293     * @apiSuccess {Number} reserveAndCancel.cancel The number of cancellations.
9294     * @apiSuccess {Object} lessonHistory The lesson history of the teacher.
9295     * @apiSuccess {Number} lessonHistoryCount The count of lessons in the lesson history.
9296     * @apiSuccess {Object} latestUserLesson The latest lesson taken by the user with the teacher.
9297     * @apiSuccess {Number} latestUserLesson.id The ID of the lesson.
9298     * @apiSuccess {Number} latestUserLesson.teacher_id The ID of the teacher.
9299     * @apiSuccess {Number} latestUserLesson.user_id The ID of the user.
9300     * @apiSuccess {Number} teacherFavoriteCount The count of users who have favorited the teacher.
9301     * @apiSuccess {Number} stusapLessonCount The count of Study Sapuri lessons conducted by the teacher.
9302     * @apiSuccess {Object[]} album The album of images for the teacher.
9303     * @apiSuccess {Number} album.id The ID of the image.
9304     * @apiSuccess {String} album.image_url The URL of the image.
9305     * @apiSuccess {Object} oOnair The on-air status of the teacher.
9306     * @apiSuccess {Number} oOnair.status The status of the on-air lesson.
9307     * @apiSuccess {String} oOnair.remarks1 Remarks about the on-air lesson.
9308     * @apiSuccess {Boolean} isFav Indicates whether the user has favorited the teacher.
9309     * @apiSuccess {Number} favoriteCount The count of users who have favorited the teacher.
9310     * @apiSuccess {Object} feature The features of the teacher.
9311     * @apiSuccess {Boolean} feature.new Indicates whether the teacher is new.
9312     * @apiSuccess {Boolean} feature.best_free_talk Indicates whether the teacher is best for free talk.
9313     * @apiSuccess {Boolean} feature.good_in_teaching_textbook Indicates whether the teacher is good in teaching textbooks.
9314     * @apiSuccess {Boolean} feature.suitable_for_intermediate_or_advance_students Indicates whether the teacher is suitable for intermediate or advanced students.
9315     * @apiSuccess {Boolean} feature.have_many_beginner_students Indicates whether the teacher has many beginner students.
9316     * @apiSuccess {Boolean} isHide Indicates whether the teacher is hidden by the user.
9317     * @apiSuccess {Boolean} unsupportedBrowser Indicates whether the user's browser is unsupported.
9318     * @apiSuccess {Boolean} canReport Indicates whether the user can report the teacher.
9319     * @apiSuccess {String} reservationTextbookConnectId The ID of the textbook connect for the reservation.
9320     * @apiSuccess {Boolean} hideLimitedPlanReservation Indicates whether to hide the limited plan reservation.
9321     * @apiSuccess {Boolean} firstTimeLoggedIn Indicates whether it is the user's first time logging in.
9322     * @apiSuccess {Number} velifyCount The count of phone verification checks.
9323     * @apiSuccess {Object[]} countryCodes The list of country codes.
9324     * @apiSuccess {String} countryCodes.country_name The name of the country.
9325     * @apiSuccess {String} countryCodes.nationality The nationality.
9326     * @apiSuccess {String} countryCodes.code The country code.
9327     * @apiSuccess {Object} userCountry The country information of the user.
9328     * @apiSuccess {String} userCountry.country_name The name of the country.
9329     * @apiSuccess {String} userCountry.national The nationality.
9330     * @apiSuccess {String} userCountry.code The country code.
9331     * @apiSuccess {Boolean} paidParent Indicates whether the user is a paid parent.
9332     * @apiSuccess {String} headtext The head text for the page.
9333     * @apiSuccess {String} title_for_layout The title for the page layout.
9334     * @apiSuccess {String} meta_description The meta description for the page.
9335     * @apiSuccess {String} meta_keywords The meta keywords for the page.
9336     * @apiSuccess {String} meta_teacher_img The URL of the teacher's image for meta tags.
9337     * @apiSuccess {Object[]} selfReviews The self-reviews of the user for the teacher.
9338     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
9339     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
9340     * @apiSuccess {Object[]} reviews The reviews of the teacher.
9341     * @apiSuccess {Number} reviews.commentCount The count of comments for the teacher.
9342     * @apiSuccess {Number} reviews.approveEvalFlag The flag indicating the approval status of the evaluations.
9343     * @apiSuccess {Number} commentCount The count of comments for the teacher.
9344     * @apiSuccess {Number} approveEvalFlag The flag indicating the approval status of the evaluations.
9345     * @apiSuccess {Object} weekly_ratings The weekly ratings of the teacher.
9346     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.id The ID of the weekly rating.
9347     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.teacher_id The ID of the teacher.
9348     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.week The week of the rating.
9349     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.year The year of the rating.
9350     * @apiSuccess {Number} weekly_ratings.TeacherWeeklyRating.rating The rating.
9351     * @apiSuccess {Object} translatedMessageParams The translated message parameters.
9352     * @apiSuccess {String} translatedMessageParams.translatedMessage The translated message.
9353     * @apiSuccess {Object} translatedSelfIntroductionThirdPpParams The translated self-introduction parameters.
9354     * @apiSuccess {String} translatedSelfIntroductionThirdPpParams.translatedSelfIntroductionThirdPp The translated self-introduction.
9355     * @apiSuccess {Object} translationModel The translation model.
9356     * @apiSuccess {Number} translationModel.id The ID of the translation.
9357     * @apiSuccess {Number} translationModel.teacher_id The ID of the teacher.
9358     * @apiSuccess {String} translationModel.lang The language of the translation.
9359     * @apiSuccess {String} translationModel.controller The controller of the translation.
9360     * @apiSuccess {Number} teacherCoinBeforeDiscount The coin amount for the teacher before discount.
9361     * @apiSuccess {Number} teacherCoinWithOp The coin amount for the teacher with options.
9362     * @apiSuccess {Boolean} nativeOptionFlg Indicates whether the native option is enabled.
9363     * @apiSuccess {Object} preset The preset textbook information.
9364     * @apiSuccess {String} preset.textbookConnectId The ID of the textbook connect.
9365     * @apiSuccess {String} preset.textbookCategoryTypeId The type ID of the textbook category.
9366     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
9367     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
9368     * @apiSuccess {Object[]} apologyList The list of apologies for reservation cancellations.
9369     * @apiSuccess {Number} apologyList.id The ID of the apology.
9370     * @apiSuccess {String} apologyList.apology The apology text.
9371     * @apiSuccess {Object} disabledSchedule The disabled schedule information.
9372     * @apiSuccess {Boolean} disabledSchedule.disabled Indicates whether the schedule is disabled.
9373     * @apiSuccess {Boolean} showNoticeMaxLimit Indicates whether to show the notice for the maximum limit.
9374     * @apiSuccess {Boolean} noIndexFlgOveride Indicates whether to override the no-index flag.
9375     * @apiSuccess {Boolean} enableNextTextbookChapterButton Indicates whether to enable the next textbook chapter button.
9376     * @apiSuccess {String} chatHash The chat hash for the lesson.
9377     * @apiSuccess {Number} lessonRequestFlg The flag indicating the lesson request status.
9378     *
9379     * @apiSuccessExample {json} Success-Response:
9380     *     {
9381     *         "teacher": {
9382     *             "id": 520,
9383     *             "name": "Teacher Name",
9384     *             "jp_name": "Teacher Name",
9385     *             "image_url": "http://example.com/image.jpg"
9386     *         },
9387     *         "country": {
9388     *             "country_name": "Country Name",
9389     *             "national": "National"
9390     *         },
9391     *         "timezone": {
9392     *             "timezone": "Asia/Tokyo"
9393     *         },
9394     *         "tutorCategory": {
9395     *             "coins": 100,
9396     *             "limited_plan_reservation": 0
9397     *         },
9398     *         "timeDiff": 32400,
9399     *         "onair": {
9400     *             "status": 1,
9401     *             "connect_flg": 1
9402     *         },
9403     *         "teacherCoin": 100,
9404     *         "callanCoin": 50,
9405     *         "teacherCallanDiscount": 20,
9406     *         "lessonCount": 10,
9407     *         "historyYear": 2,
9408     *         "historyMonth": 3,
9409     *         "keep_memo": {
9410     *             "memo": "Memo"
9411     *         },
9412     *         "reserveAndCancel": {
9413     *             "reserve": 5,
9414     *             "cancel": 2
9415     *         },
9416     *         "lessonHistory": {},
9417     *         "lessonHistoryCount": 5,
9418     *         "latestUserLesson": {
9419     *             "id": 123,
9420     *             "teacher_id": 520,
9421     *             "user_id": 456
9422     *         },
9423     *         "teacherFavoriteCount": 100,
9424     *         "stusapLessonCount": 50,
9425     *         "album": [
9426     *             {
9427     *                 "id": 1,
9428     *                 "image_url": "http://example.com/image1.jpg"
9429     *             }
9430     *         ],
9431     *         "oOnair": {
9432     *             "status": 1,
9433     *             "remarks1": "Remarks"
9434     *         },
9435     *         "isFav": true,
9436     *         "favoriteCount": 200,
9437     *         "feature": {
9438     *             "new": true,
9439     *             "best_free_talk": true,
9440     *             "good_in_teaching_textbook": true,
9441     *             "suitable_for_intermediate_or_advance_students": true,
9442     *             "have_many_beginner_students": true
9443     *         },
9444     *         "isHide": false,
9445     *         "unsupportedBrowser": false,
9446     *         "canReport": true,
9447     *         "reservationTextbookConnectId": "123",
9448     *         "hideLimitedPlanReservation": false,
9449     *         "firstTimeLoggedIn": true,
9450     *         "velifyCount": 1,
9451     *         "countryCodes": [
9452     *             {
9453     *                 "country_name": "Country Name",
9454     *                 "nationality": "National",
9455     *                 "code": "Code"
9456     *             }
9457     *         ],
9458     *         "userCountry": {
9459     *             "country_name": "Country Name",
9460     *             "national": "National",
9461     *             "code": "Code"
9462     *         },
9463     *         "paidParent": false,
9464     *         "headtext": "Teacher Name",
9465     *         "title_for_layout": "Teacher Name - 講師詳細 | オンライン英会話のネイティブキャンプ",
9466     *         "meta_description": "Teacher description",
9467     *         "meta_keywords": "Teacher Name,講師,オンライン英会話,ネイティブキャンプ",
9468     *         "meta_teacher_img": "http://example.com/image.jpg",
9469     *         "selfReviews": [...],
9470     *         "selfLessonCount": 5,
9471     *         "daysPast": 10,
9472     *         "reviews": [
9473     *             {
9474     *                 "commentCount": 50,
9475     *                 "approveEvalFlag": 1
9476     *             }
9477     *         ],
9478     *         "commentCount": 50,
9479     *         "approveEvalFlag": 1,
9480     *         "weekly_ratings": {
9481     *             "TeacherWeeklyRating": {
9482     *                 "id": 123,
9483     *                 "teacher_id": 520,
9484     *                 "week": 1,
9485     *                 "year": 2021,
9486     *                 "rating": 5
9487     *             }
9488     *         },
9489     *         "translatedMessageParams": {
9490     *             "translatedMessage": "Translated message"
9491     *         },
9492     *         "translatedSelfIntroductionThirdPpParams": {
9493     *             "translatedSelfIntroductionThirdPp": "Translated self-introduction"
9494     *         },
9495     *         "translationModel": {
9496     *             "id": 123,
9497     *             "teacher_id": 520,
9498     *             "lang": "en",
9499     *             "controller": "WaitingController"
9500     *         },
9501     *         "teacherCoinBeforeDiscount": 120,
9502     *         "teacherCoinWithOp": 130,
9503     *         "nativeOptionFlg": true,
9504     *         "preset": {
9505     *             "textbookConnectId": "456",
9506     *             "textbookCategoryTypeId": "789"
9507     *         },
9508     *         "textbookConnectId": "456",
9509     *         "textbookCategoryTypeId": "789",
9510     *         "apologyList": [
9511     *             {
9512     *                 "id": 1,
9513     *                 "apology": "Apology"
9514     *             }
9515     *         ],
9516     *         "disabledSchedule": {
9517     *             "disabled": true
9518     *         },
9519     *         "showNoticeMaxLimit": false,
9520     *         "noIndexFlgOveride": false,
9521     *         "enableNextTextbookChapterButton": true,
9522     *         "chatHash": "example_chat_hash",
9523     *         "lessonRequestFlg": 1
9524     *     }
9525     *
9526     * @apiError {String} error Message indicating the error.
9527     *
9528     * @apiErrorExample {json} Error-Response:
9529     *     {
9530     *         "error": "Invalid request."
9531     *     }
9532     * 
9533     * @apiSampleRequest off
9534     */
9535    public function avatar_detail($teacherId = 520, $highLightFlag = null) {
9536        if (is_null($teacherId)) {
9537            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
9538        }
9539
9540        $this->avatarLatestLessonHistory($this->Auth->user('id'), $teacherId);
9541        //set mobile view
9542        if (myTools::defaultAction($this)) {
9543            return $this->spAvatarDetail($teacherId);
9544        }
9545
9546        $checkParams = array(
9547            'type' => 'count',
9548            'args' => array(
9549                'conditions' => array(
9550                    'id' => $teacherId,
9551                    'avatar_parent_flg' => 0
9552                ),
9553                'recursive' => -1
9554            )
9555        );
9556
9557        // - NC-3802: redirect to mypage if not avatar parent teacher
9558        if ($this->Teacher->getTeachers($checkParams)) {
9559            return $this->redirect('/mypage');
9560        }
9561
9562        if (BlockListTable::isUserBlocked($this->Auth->User('id'), $teacherId) == true) {
9563            return $this->redirect('/waiting');
9564        }
9565        //redirect to proper profile
9566        $this->checkProperProfile($teacherId);
9567
9568        $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
9569        $queryCondition = array(
9570            'fields' => array(
9571                    'TeacherRankCoin.coins',
9572                    'LessonOnair.id',
9573                    'LessonOnair.teacher_id',
9574                    'LessonOnair.user_id',
9575                    'TeacherRankCoin.limited_plan_reservation'
9576                ),
9577            'joins' => array(
9578                array(
9579                    'type' => 'LEFT',
9580                    'table' => 'teacher_rank_coins',
9581                    'alias' => 'TeacherRankCoin',
9582                    'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
9583                )
9584            ),
9585            'conditions' => array(
9586                array('Teacher.id' => $teacherId)
9587            ),
9588            'show' => 'first'
9589        );
9590
9591        $commonTeacherStatusParams = array(
9592            'page_display' => 'listTeacher',
9593            'query_conditions' => $queryCondition
9594        );
9595        $data = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
9596
9597        if (!$data) {
9598            return $this->redirect('/waiting/');
9599        }
9600
9601        //redirect if withdrawn teacher or teacher is block in NJ-43859
9602        if ($data['Teacher']['status'] <> 1  || $data['Teacher']['inactive_flg'] == 1 || in_array($data['Teacher']['rank_coin_id'], $this->blockMemberSettings)) {
9603            if ($this->Auth->loggedIn()) {
9604                return $this->redirect(myTools::geturl() . '/mypage');
9605            } else {
9606                return $this->redirect(myTools::geturl() . '/waiting');
9607            }
9608        }
9609
9610        if (isset($data['LessonOnair'])) {
9611            $tmp = (object) $data['LessonOnair'];
9612            if (!$tmp->id) {
9613                $data['LessonOnair'] = null;
9614            }
9615        }
9616
9617
9618
9619        // get teacher information
9620        $teacher = new TeacherTable($data['Teacher']);
9621
9622        $country = new TeacherTable($data['CountryCode']);
9623        $timezone = new TimezoneTable($data['Timezone']);
9624        $tutorCategory = new TeacherRankCoinTable($data['TeacherRankCoin']);
9625
9626        // Avatar var
9627        $avatarTeacherId = $teacherId;
9628        $teacherName = isset($teacher->jp_name) ? $teacher->jp_name : null;
9629        $teacherNameEn = isset($teacher->name) ? $teacher->name : null;
9630        $teacherImageSrc = $teacher->getImageUrl();
9631
9632        $timeDiff = 0;
9633        if (isset($timezone->continent_id) && isset($timezone->city_eng)) {
9634            $timeDiffData = $this->Timezone->computeTimeDiff(array(
9635                'continent_id' => $timezone->continent_id,
9636                'city' => $timezone->city_eng
9637            ));
9638
9639            //
9640            if ($timeDiffData['success']) {
9641                $timeDiff = $timeDiffData['timeDiff'];
9642            }
9643        }
9644
9645        $onair = $data['LessonOnair'];
9646
9647        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9648        # Get teachers reservation amounts.
9649        $req_params =  array(
9650                'basic_amount_type' => 15,
9651                'current_rank_id' => $teacherCurrentRankId
9652            );
9653        $teacherCoin = $this->HomeBasedRankBasicAmountLog->getBasicAmount($req_params);
9654
9655        //
9656        $teacherCurrentRankId = ClassRegistry::init('Teacher')->getTeacherCurrentRankId($teacher->id);
9657
9658        // get user data
9659        $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
9660
9661        # Get teachers reservation amounts. | NJ-2038, for hb teachers only not applicable for counselor/avatar
9662        $coinParams =  array(
9663            'current_rank_id' => $teacherCurrentRankId,
9664            'reserve_coin_data_id' => $teacher->reserve_coin_data_id,
9665            'reserve_coin_settings_flg' => $tutorCategory->reserve_coin_settings_flg,
9666            'student_native_option' => $userData['native_option'],
9667            'home_flg' => $teacher->home_flg,
9668            'counseling_flg' => $teacher->counseling_flg,
9669            'avatar_parent_flg' => $teacher->avatar_parent_flg,
9670            'avatar_flg' => $teacher->avatar_flg,
9671            'native_speaker_flg' => $teacher->native_speaker_flg
9672        );
9673
9674        // get teacher coin settings
9675        $teacherCoinData = $this->Teacher->getTeacherReserveCoin($coinParams);
9676
9677        $teacherCoinWithOp = $teacherCoinBeforeDiscount = null;
9678        $displayNativeOptionAmountFlg = false;
9679        if($teacherCoinData){
9680            // set teacher reservation coin
9681            $teacherCoin = (isset($teacherCoinData['reserve_coin']) && is_numeric($teacherCoinData['reserve_coin'])) ? $teacherCoinData['reserve_coin'] : 0;
9682            $teacherCoinBeforeDiscount = $teacherCoinData['reserve_coin_before_discount'];
9683            $teacherCoinWithOp = $teacherCoinData['reserve_coin_with_op'];
9684            $displayNativeOptionAmountFlg = $teacherCoinData['display_native_option_amount_flg'];
9685        }
9686
9687        $callanCoin = ($teacher->callan_halfprice_flg) ? $teacherCoin / 2 : $teacherCoin;
9688
9689        $teacherCallanDiscount = $teacher->getCallanHalfPrice();
9690
9691        $userId = ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null;
9692
9693        //number of lesson
9694        $lessonCount = $this->LessonOnairsLog->countTeacherLessons(['teacherId' => $teacherId, 'avatar' => 1]);
9695
9696        [$historyYear, $historyMonth] = $teacher->getTotalTeachingExperience();
9697
9698        $this->set('historyMonth',$historyMonth);
9699        $this->set('historyYear',$historyYear);
9700
9701        //NJ-20069 avatar detail changes
9702        $getKeepMemo = $this->UsersMemo->find('first', array(
9703            'fields' => array(
9704                'id',
9705                'memo'
9706            ),
9707            'conditions' => array(
9708                'user_id' => $this->Auth->user('id'),
9709                'teacher_id' => $teacherId,
9710                'type' => 0
9711            ),
9712            'order' => array('created DESC'),
9713        ));
9714
9715        $this->set('keep_memo', $getKeepMemo);
9716
9717        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9718        $lessonHistory = $this->LessonSchedule->latestLessonHistory($teacherId, $this->Auth->user('id'), $this->localizeDir, null, "avatar");
9719        $lessonHistoryCount  = is_iterable(($lessonHistory['lessonHistory'])) ? count($lessonHistory['lessonHistory']) : 0;
9720        $latestUserLesson = ($lessonHistory['lessonHistory'][0]['LessonOnairsLog']);
9721        $teacherFavoriteCount = $this->UsersFavorite->getFavoriteCount($teacherId);
9722        $stusapLessonCount = $this->Teacher->getAvatarSapuriLessonCount($teacherId);
9723
9724        // - if has translated Category name
9725        if (isset($lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) && $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name']) {
9726            $lessonHistory['lessonHistory'][0]['TextbookCategory']['name'] = $lessonHistory['lessonHistory'][0]['GlobalTextbookCategory']['gl_name'];
9727        }
9728
9729        $formattedLatestLessonData = "";
9730        if(!empty($latestUserLesson))
9731        $formattedLatestLessonData = date('Y-m-d',strtotime($latestUserLesson['start_time'])). " (" . date('D',strtotime($latestUserLesson['start_time'])) . ") ";
9732
9733        $this->set('lessonHistoryCount', $lessonHistoryCount);
9734        $this->set('latestUserLesson', $lessonHistory['lessonHistory'][0]);
9735        $this->set('teacherRates', $reserveAndCancel);
9736        $this->set('teacherIdCheck', $teacherId);
9737        $this->set('latestLessonData', $formattedLatestLessonData);
9738        $this->set('lessonHistory', $lessonHistory);
9739        $this->set('teacherId', $teacherId);
9740        $this->set('teacherFavoriteCount', $teacherFavoriteCount);
9741        $this->set('stusapLessonCount', $stusapLessonCount);
9742        $this->set('stusapLessonCount', (int) $teacher->stusap_lesson_count + (int) $teacher->stasapu_tos_lesson_count);
9743
9744
9745
9746        // album
9747        $this->TeacherImage->openDBReplica();
9748        $album = $this->TeacherImage->find('all', array(
9749            'fields' => array(
9750                'TeacherImage.id',
9751                'TeacherImage.teacher_id',
9752                'TeacherImage.approve_flg',
9753                'TeacherImage.is_profile',
9754                'TeacherImage.approve_required',
9755                'FileStorage.url'
9756            ),
9757            'conditions' => array(
9758                'TeacherImage.teacher_id' => $teacherId,
9759                'TeacherImage.is_profile' => 0,
9760                'OR' => array(
9761                    'OR' => array(
9762                            'TeacherImage.approve_flg' => 1,
9763                            'TeacherImage.approve_required' => 0
9764                        )
9765                    )
9766            ),
9767            'joins' => array(
9768                array(
9769                    'type' => 'INNER',
9770                    'table' => 'file_storage',
9771                    'alias' => 'FileStorage',
9772                    'conditions' => array(
9773                        'TeacherImage.file_storage_id = FileStorage.id',
9774                        'FileStorage.uploader_type = 3',
9775                        'FileStorage.uploader_id' => $teacherId
9776                    )
9777                )
9778            ),
9779            'order' => array('TeacherImage.id DESC')
9780        ));
9781        $this->TeacherImage->closeDBReplica();
9782
9783        $this->set('album', $album);
9784
9785        //lesson onair
9786        if (!empty($onair)) {
9787            $oOnair = new LessonOnairTable($onair);
9788        } else {
9789            //teacher_status if login or break
9790            $teacherStatus1 = $this->TeacherStatus->find('first', array(
9791                'fields' => array('TeacherStatus.status', 'TeacherStatus.remarks1', 'TeacherStatus.remarks2'),
9792                'conditions' => array('TeacherStatus.teacher_id' => $teacher->getId())
9793            ));
9794            if (!empty($teacherStatus1)) {
9795                $oOnair = new TeacherStatusTable($teacherStatus1['TeacherStatus']);
9796            } else {
9797                $oOnair = 0;
9798            }
9799        }
9800
9801        //favorite
9802        $where = array(
9803            'UsersFavorite.user_id'     => $this->Auth->user('id'),
9804            'UsersFavorite.teacher_id'     => $teacherId,
9805        );
9806        $isFav = $this->UsersFavorite->find('count', array('conditions' => $where));
9807        $where = array(
9808            'UsersFavorite.teacher_id'  => $teacherId,
9809        );
9810        $favoriteCount = $this->UsersFavorite->find('count', array('conditions' => $where));
9811        $where = array(
9812            'TeacherFeature.teacher_id' => $teacherId,
9813        );
9814        $feature = $this->TeacherFeature->find('first', array('conditions' => $where));
9815
9816        // NC-5897 : check if teacher was hide by user.
9817        $where = array(
9818            'user_id' => $this->Auth->user('id'),
9819            'teacher_id' => $teacherId,
9820        );
9821        $isHide = $this->BlockList->isTeacherHide($where);
9822
9823        $feature = isset($feature['TeacherFeature']) ? new TeacherFeatureTable($feature['TeacherFeature']) : new TeacherFeatureTable(array());
9824        $this->User->recursive = -1;
9825        $data = $this->User->findById($userId);
9826        $user = isset($data['User'])?$data['User']: null;
9827        $unsupportedBrowser = false;
9828        $browser =  $this->request->header('User-Agent');
9829
9830        if (preg_match('/(Edg|Edge)/i',$browser) ) {
9831            $unsupportedBrowser = false;
9832        } elseif (!preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
9833            $unsupportedBrowser = true;
9834        }
9835        $canReport = true;
9836        $reservationTextbookConnectId = "";
9837        if ($user) {
9838            $userData = new UserTable($data['User']);
9839            $userMembership = $userData->getUserMembership();
9840            $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
9841            $this->set('user_lang', $userData->native_language2);
9842            // if weekly plan user
9843            $corporateUser = isset($corporateType) ? $corporateType : '';
9844
9845            $userMemberTypeCantReportTeacher = Configure::read('user_member_type.cant_report_teacher');
9846            $canReport = $userData->getMembershipTypeIndex();
9847            $canReport = in_array($canReport, $userMemberTypeCantReportTeacher) ? false : true;
9848            //NJ-24096: get last reservation textbook type
9849            $sapuriFlg = ($this->isStudySapuriTosUser || $this->isStudySapuriUser) ? true :false;
9850            $lastReservationData = LessonScheduleTable::getLastReservation($userId, $sapuriFlg);
9851
9852            if (!empty($lastReservationData['LessonSchedule']['connect_id'])) {
9853                $reservationTextbookConnectId = $lastReservationData['LessonSchedule']['connect_id'];
9854            } else {
9855                $this->User->openDBReplica();
9856                $checkUserFirstFlg = $this->LessonSchedule->field('connect_id', array('user_id' => $userId));
9857                $this->User->closeDBReplica();
9858                if (empty($checkUserFirstFlg)) {
9859                    $defaultParams = array(
9860                        'user_id' => $userId,
9861                        'lang' => $userData->native_language2
9862                    );
9863                    $defaultReservation = $this->Textbook->getDefaultReservationTBConnectId($defaultParams);
9864                    if ($defaultReservation) {
9865                        $reservationTextbookConnectId = $defaultReservation;
9866                    }
9867                }
9868            }
9869        }
9870        $this->set(compact('reservationTextbookConnectId'));
9871        $this->set('unsupportedBrowser', $unsupportedBrowser);
9872        // NC-6615 check if user can report the teacher
9873        $this->set('canReport', $canReport);
9874
9875        $hideLimitedPlanReservation = false;
9876        if ($tutorCategory->limited_plan_reservation == 0 && (isset($corporateUser) && $corporateUser ==  Configure::read('corporate_type.limited'))) {
9877            $hideLimitedPlanReservation = true;
9878        }
9879
9880        $firstTimeLoggedIn = false;
9881        if (!$user['last_login_time']) {
9882            $firstTimeLoggedIn = true;
9883        }
9884
9885        $paidParent = false;
9886
9887        $velifyCount = $this->PhoneVerifyCheckLog->find('count',array(
9888            'conditions' => array(
9889                'user_id' => $this->Auth->user('id'),
9890                'status' => 0
9891            )
9892        ));
9893
9894        $countryCodes = $this->CountryCode->find('all',array(
9895            'fields' => array(
9896                'code',
9897                'country_name'
9898            ),
9899            'order' => 'country_name ASC'
9900        ));
9901        $this->set('countryCodes',$countryCodes);
9902
9903        $userCountry['CountryCode']['country_name'] = '';
9904        $userCountry['CountryCode']['code'] = '';
9905        if(!empty($data['User']['country_code'])){
9906            $userCountry = $this->CountryCode->find('first',array(
9907                'conditions' => array(
9908                    'code' => $data['User']['country_code']),
9909                'fields' => array(
9910                    'code',
9911                    'country_name')
9912            ));
9913            if(empty($userCountry)){
9914                $userCountry['CountryCode']['code'] = '';
9915            }
9916        }
9917        $this->set('countryCodes',$countryCodes);
9918
9919        //check if user is child by checking its parent id not empty
9920        if (isset($data['User']['parent_id'])) {
9921            $paidParent = $this->User->checkPaidParent($data['User']['parent_id']);
9922        }
9923        #$lesson_count=0;
9924        // 管理者権限会員は無制限でレッスン出来る
9925        if ($user['admin_flg']=='1') {
9926            $user['charge_flg'] = 1;
9927            $lesson_count=0;
9928            $lesson_count_today = 0;
9929        }
9930
9931        if (empty($user['enquate6'])) {
9932            $user['enquate6'] = '1';
9933        }
9934
9935        if (empty($user['enquate7'])) {
9936            $user['enquate7'] = '1';
9937        }
9938        // - prepare head text
9939        $headTextWD = $pageTitleWD = $teacherNameEn;
9940        $metaDescWD = "";
9941        if ($this->localizeDir == Configure::read('default.user_language')) {
9942            $headTextWD .= '('.$teacherName.')';
9943            $pageTitleWD .=  '('.$teacherName.')';
9944            //$metaDescWD .= '('.$teacherName.')';
9945        }
9946        $pageTitleWD .= '&ensp;-&ensp;'. __d('default_pc','講師詳細 | オンライン英会話のネイティブキャンプ');
9947        //$metaDescWD .= __d('waiting','講師の紹介ページです。').$teacher->getMetaDescription();
9948
9949        //prepare meta image 
9950        $_teacherImgUrl = $teacher->getImageUrl();
9951
9952        //check if teacher has no image 
9953        if (empty($teacher->image_url) || !$teacher->image_url) {
9954            $defaultTeacherImg = myTools::getUrl() . '/teacher/img/no_profile_img.jpg';
9955            $_teacherImgUrl = ($_teacherImgUrl == $defaultTeacherImg) ? $_teacherImgUrl : $defaultTeacherImg;
9956        }
9957
9958        // - set page meta information
9959        $this->set('headtext', $headTextWD);
9960        $this->set('title_for_layout', $pageTitleWD);
9961        //$this->set('meta_description', $metaDescWD);
9962        $this->set('meta_keywords',$teacher->name.',講師,オンライン英会話,ネイティブキャンプ');
9963        $this->set('counselingFlg',$teacher->counseling_flg);
9964        $this->set('meta_teacher_img',$_teacherImgUrl);
9965        //get own reviews
9966        $selfReviews = array();
9967        $selfLessonCount = 0;
9968        $daysPast = 0;
9969        if ($userId) {
9970            $selfReviews = $this->getUserReviews($userId, $teacherId);
9971            $userLessonDetail = $this->LessonOnairsLog->getUserLessonCount($userId, $teacherId);
9972            $selfLessonNow = $userLessonDetail['lessonCount'];
9973            $selfReservation = $userLessonDetail['reserveCount'];
9974            $selfLessonCount = $selfLessonNow + $selfReservation;
9975            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
9976        }
9977        //reservation and cancellation breakdown
9978        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
9979
9980        $options = $this->Auth->user('id') ? array('userId' => $this->Auth->user('id')) : array();
9981        $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir,true);
9982        $options['language_id'] = $reviewLanguage[0];
9983        $options['not_language_ids'] = $reviewLanguage[1] ?? null;
9984        $options['avatar'] = 1;
9985
9986        $userTable = new UserTable($this->Auth->user());
9987        $sapuriPlan = $userTable->isStudySapuri();
9988        $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
9989        if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
9990            $options['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
9991        } else {
9992            $options['textbook_category_type_not_in'] = $sapuriTextbookType;
9993        }
9994
9995        $reviews = $this->UsersClassEvaluation->getComments($teacherId, 0, 4, $options);
9996        $commentCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
9997        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
9998
9999        # get weekly rating
10000        $approveFlag = $this->UsersClassEvaluation->getApproveEvalCount($teacherId);
10001
10002        $get_weekly_rating = $this->UsersClassEvaluation->getAvatarRatings($teacherId);
10003        
10004        /* -- NC-5293 start -- */
10005        $this->loadModel('Translation');
10006        $translationCategories = Configure::read('translation_categories');
10007        $translateParams = array(
10008            'languageCode' => $this->lang_iso,
10009            'categoryId' => $translationCategories['teacher_message'],
10010            'messageId' => $teacher->id,
10011            'text' => $teacher->message
10012        );
10013
10014        $translatedMessageParams = $translateParams;
10015        $translateParams['categoryId'] = $translationCategories['teacher_self_introduction_third_pp'];
10016        $translateParams['text'] = $teacher->self_introduction_third_pp;
10017        $translatedSelfIntroductionThirdPpParams = $translateParams;
10018        /* -- NC-5293 end -- */
10019
10020        // Translate and save translated data
10021        $globalTranslate = TeacherTable::translate(array(
10022            'id' => $teacherId,
10023            'lang'=> isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language'),
10024            'controller' => static::class
10025        ));
10026        $translatedMessageTranslation = isset($globalTranslate['message']) ? $globalTranslate['message'] : null;
10027        $translatedThirdppTranslation = isset($globalTranslate['self_introduction_third_pp']) ? $globalTranslate['self_introduction_third_pp'] : null;
10028        $this->set('message', $translatedMessageTranslation);
10029        $this->set('intro', $translatedThirdppTranslation);
10030
10031        //find the selfintro 
10032        $TeacherTable = new TeacherTable($teacher);
10033        $_userSelfIntro = $TeacherTable->iSNotDisplayHtmlTags($teacher->message);
10034        $_userSelfIntro = strip_tags($_userSelfIntro);
10035
10036        //set the new meta description
10037        $metaDescWD = TeacherTable::getMetaDescription2($_userSelfIntro);
10038        $this->set('meta_description', $metaDescWD);
10039    
10040        $favIds = $isFav ? [$teacher->id] : [];
10041        $teacherFavColor = $this->UsersFavoriteCategoriesTeacher->getColorFavTeacherByIds(['user_id' => $this->Auth->user('id'), 'teacher_ids' => $favIds]);
10042        $teacherFavsColors = $this->UsersFavoriteCategoriesTeacher->parseToHexColor([
10043            'favIds' => $favIds,
10044            'favIdsTeacherCategory' => $teacherFavColor
10045        ]);
10046        // set view vars
10047        $setData = array(
10048            'teacher' => $teacher,
10049            'onair' => $oOnair,
10050            'isFav' => $isFav,
10051            'teacherFavsColors' => $teacherFavsColors,
10052            'isHide' => $isHide,
10053            'favoriteCount' => $favoriteCount,
10054            'feature' => $feature,
10055            'tId' => $teacher->id,
10056            'user' => $user,
10057            'lessonAvailable' => isset($lessonAvailable['lessonAvailable']) ? $lessonAvailable['lessonAvailable'] : 0,
10058            'userMembership' => isset($userMembership)?$userMembership:'',
10059            'adminFlag' => isset($user['admin_flg'])?$user['admin_flg']:'0',
10060            'enquate6_options' => UserTable::getEnquate6(),
10061            'enquate7_options' => UserTable::getEnquate7(),
10062            'reviews' => $reviews,
10063            //'rates' => $rates,
10064            'approveEvalFlag' => $approveFlag,
10065            'weekly_ratings' => isset($get_weekly_rating) ? $get_weekly_rating['TeacherWeeklyRating'] : 0,
10066            'userId' => $userId,
10067            'cardAuth' => PaymentTable::checkIfCardAuth($this->Auth->user('id'), $this->Auth->user('hash16')),
10068            'teacherCoin' => empty($teacherCoin)? 0: (int)$teacherCoin,
10069            'callanCoin' => (int)$callanCoin,
10070            'teacherCallanDiscount' => empty($teacherCallanDiscount)? 0: $teacherCallanDiscount,
10071            'UserData' => $data,
10072            'userCountry' => $userCountry,
10073            'velifyCount' => $velifyCount,
10074            'firstTimeLoggedIn' => $firstTimeLoggedIn,
10075            //'rateBreakdown' => $rateBreakdown,
10076            'selfReviews' => $selfReviews,
10077            'selfLessonCount' => $selfLessonCount,
10078            'daysPast' => $daysPast,
10079            'reserveAndCancel' => $reserveAndCancel,
10080            'isLoggedIn' => $this->Auth->loggedIn(),
10081            'country' => $country,
10082            'timeDiff' => $timeDiff,
10083            'corporateId' => !empty($data['User']['corporate_id']) ? $data['User']['corporate_id'] : $this->Auth->user('corporate_id'),
10084            'translatedMessageParams' => $translatedMessageParams,
10085            'translatedSelfIntroductionThirdPpParams' => $translatedSelfIntroductionThirdPpParams,
10086            'translationModel' => $this->Translation,
10087            'hideLimitedPlanReservation' => $hideLimitedPlanReservation,
10088            'teacherCoinBeforeDiscount' => empty($teacherCoinBeforeDiscount)? 0: (int)$teacherCoinBeforeDiscount,
10089            'teacherCoinWithOp' => empty($teacherCoinWithOp)? 0: (int)$teacherCoinWithOp,
10090            'nativeOptionFlg' => $displayNativeOptionAmountFlg,
10091            'lessonCount' => $lessonCount,
10092        );
10093
10094        $this->set($setData);
10095        $this->set('avatar_teacher_detail', 1);
10096        if ($userId) {
10097            $points = $this->UsersPoint->find('first', array(
10098                'fields' => array('point'),
10099                    'conditions' => array(
10100                        'user_id' => $userId
10101                    )
10102                )
10103            );
10104
10105            $points = isset($points['UsersPoint']['point']) ? $points['UsersPoint']['point'] : 0;
10106            $reservePoint = Configure::read("reserve_point");
10107
10108            if (intval($reservePoint) < 1) $reservePoint = 0;
10109            //set promo discount for reservation
10110            // set paramater to 2 for reservation promo
10111            $bonus = CoinSetTable::getCoinSet(2);
10112            //check if the promo is valid today
10113            if ($bonus) {
10114                $reservePoint = $bonus;
10115            }
10116        } else {
10117            $points = 0;
10118        }
10119
10120        # get user timezone
10121        $user_timezone_id = (isset($this->sharedUserData['User']['timezone_id'])) ? $this->sharedUserData['User']['timezone_id'] : 203;
10122        $user_timezone_data = $this->Timezone->find('first',
10123            array(
10124                'fields' => array(
10125                    'Timezone.city_eng',
10126                    'Timezone.utc_offset',
10127                    'Timezone.country_code_id'
10128                ),
10129                'conditions' => array(
10130                    'Timezone.id' => $user_timezone_id
10131                ),
10132                'recursive' => -1
10133            )
10134        );
10135
10136        // - NJ-3653 get country
10137        $countryTimezone = null;
10138        if (!empty($user_timezone_data) && $user_timezone_data['Timezone']['country_code_id']) {
10139            // - Get all country Code
10140            $countryOptions = $this->Timezone->countryOptions();
10141
10142            $countryCodeId = $user_timezone_data['Timezone']['country_code_id'];
10143            $countryName = $countryOptions[$countryCodeId]['country_name'];
10144
10145            if (isset($countryName) && $countryName) {
10146                $countryTimezone = $countryName;
10147            }
10148        }
10149
10150
10151        $this->set('countryTimezone', $countryTimezone);
10152        $this->set('userTimezoneData', $user_timezone_data);
10153
10154        #user time
10155        $datetime = date('Y-m-d H:i:s');
10156        $localTime = $this->displayTime;
10157        // NJ-29496
10158        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("custom_lang_format_support"))) { 
10159            $formattedDate = date('d/m/Y G:i', $localTime);
10160        } else {
10161            $formattedDate = date('Y/m/d G:i', $localTime);
10162        }
10163    
10164        $this->set('userCurrentTime', $formattedDate);        
10165
10166        $this->set('points', $points);
10167        $this->set('reservePoint', isset($reservePoint)? $reservePoint: 0);
10168
10169        $countrids_no = Configure::read('sms_send.countrids_no');
10170        $this->set('countrids_no', $countrids_no);
10171
10172        $deviceNotSupported = false;
10173        $ua = (!empty(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']))) ? myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) : '';
10174        if (strpos($ua, 'Android') !== false || strpos($ua, 'iPhone') !== false || strpos($ua, 'iPad') !== false || strpos($ua, 'iPod') !== false) {
10175            $deviceNotSupported = true;
10176        }
10177        $this->set('deviceNotSupported', $deviceNotSupported);
10178
10179        $this->set('statusCheck', array(1, 4));
10180
10181        $this->set('login', $this->Auth->loggedIn());
10182
10183        //get preset textbook -> last viewed -> default textbook category first lesson
10184        $presetParams = array("user_id" => $this->Auth->User('id'));
10185
10186        //add additional parameters
10187        if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
10188            $presetParams["lang"] = $this->localizeDir;
10189        }
10190        //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
10191        $presetParams["userValidForSSBEDT"] = $this->userValidForSSBEDT();
10192
10193        #NC-9916
10194        if($data['User']) {
10195            $presetParams['native_language2'] = $userData->native_language2;
10196            $presetParams["userMembershipType"] = $userData->getMembershipTypeIndex();
10197        }
10198        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
10199
10200        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
10201            # for preset
10202            $presetParams['connect_id'] = $preset_data['preset_connect_id'];
10203            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10204
10205        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
10206            # use last viewed textbook if no preset data.
10207            $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
10208            $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
10209
10210        }
10211
10212        // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
10213        $presetParams['is_pc_flg'] = 1;
10214
10215        # fetch preset
10216        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10217        if(!$preset) {
10218            unset($presetParams['connect_id']);
10219            unset($presetParams['last_opened_date']);
10220            $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
10221        }
10222
10223        // NC-8020
10224        $this->set('textbookConnectId', $preset['textbook_connect_id']);
10225        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
10226
10227        //set variable preset textbook to be displayed
10228        $this->set('preset', $preset);
10229        // apology list (cancellation of reservation)
10230         $apologyList = array(); // NC-4749 : hide list, used function from model and made it popup modal
10231        $this->set('apologyList', $apologyList);
10232
10233        $getAvatarParams = array(
10234            "avatar_id" => $teacherId,
10235            "user_id" => $this->Auth->user('id'),
10236            "stealth_flg" => $this->Cookie->read('stealth.setting')
10237        );
10238        $avatarTeacherIds = $this->Teacher->getAvatarTeacherId($getAvatarParams);
10239
10240        // NJ-18780 : check if user is normal lite plan
10241        $_paymentPlanID = isset($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null;
10242        $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
10243
10244
10245        $disabledSchedule = $this->LessonSchedule->getDisabledDaysPC(array(
10246            'userId' => $this->Auth->user('id'),
10247            'teacherId' => $avatarTeacherIds,
10248            'timeDiff' => $this->timeDiff,
10249            'isNormalLitePlanUser' => $isNormalLitePlanUser
10250        ));
10251
10252        // dynamic techer
10253
10254        $avatarParams = array(
10255            "user_id" => $this->Auth->user('id'),
10256            "avatar_id" => $teacherId
10257        );
10258
10259        $avatarTeacherArr = $this->Avatar->availableTeacher($avatarParams);
10260        $lessTime = 0;
10261        if ( isset($avatarTeacherArr["teacher_id"]) ) {
10262            $avatarTeacherId = $avatarTeacherArr["teacher_id"];
10263        }
10264        if ( isset($avatarTeacherArr["less_time"]) ) {
10265            $lessTime = $avatarTeacherArr["less_time"];
10266        }
10267        $options['isAvatar'] = 1;
10268        $reviewsCount = $this->UsersClassEvaluation->getCommentCount($teacherId, $options);
10269
10270        $this->set('order', $this->Cookie->read('teacherReviewOrder') ?? 0);
10271        $this->set('reviewsCount', $reviewsCount);
10272        $this->set('teacherName', $teacherName);
10273        $this->set('teacherImageSrc', $teacherImageSrc);
10274        $this->set('lessTime', $lessTime);
10275        $this->set('isAvatar',true);
10276        $this->set('avatarTeacherId', $avatarTeacherId);
10277        $this->set('disabledSchedule', json_encode($disabledSchedule));
10278        $this->set('showNoticeMaxLimit', (isset($disabledSchedule['disableAll']) ? $disabledSchedule['disableAll'] : false));
10279        $this->set('noIndexFlgOveride', ($this->localizeDir != Configure::read('default.user_language') ? true : false));
10280
10281        // - NJ-6390 add highLightFlag
10282        $this->set('highLightFlag', isset($highLightFlag) && $highLightFlag? $highLightFlag: null);
10283
10284        // class evaluation
10285        if ($this->request->query('chatHash')) {
10286            $chatHash = $this->request->query('chatHash');
10287
10288            // Check if chatHash is valid
10289            $this->LessonOnairsLog->openDBReplica();
10290            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
10291            $this->LessonOnairsLog->closeDBReplica();
10292
10293            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
10294                $this->LessonOnair->openDBReplica();
10295                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
10296                $this->LessonOnair->closeDBReplica();
10297
10298                if(!$allData) {
10299                    return $this->redirect(array('controller' => 'home', 'action' => 'index', 'home'));
10300                }
10301            }
10302
10303            $userValidForSSBEDT = false;
10304            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
10305                $userValidForSSBEDT = true;
10306            }
10307            $param = array(
10308                "user_id" => $userId,
10309                "select_method" => "first",
10310                "env_flag" => "all",
10311                'connect_id' => $allData['Connect']['id'],
10312                "user_locale" => $this->localizeDir,
10313                "userValidForSSBEDT" => $userValidForSSBEDT
10314            );
10315            
10316            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
10317                $corporateParams = array('user_id' => $userId);
10318                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10319                
10320                if ($corporateTextbookControlFlg == 1) {
10321                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
10322                    if (!empty($categoryData)) {
10323                        $param['include_kids_category'] = $allData['Connect']['category_id'];
10324                    }
10325                }
10326            }
10327            $textbookData = $this->Textbook->getTextbooks($param);
10328            $data = $textbookData['res_data'];
10329
10330            $isReservedLesson = 2;
10331            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
10332            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
10333            $latestPresetTextbookConnect_categoryId = (int)$data['TextbookConnect']['category_id'];
10334            $latestPresetTextbookConnect_subCategoryId = (int)$data['TextbookConnect']['subcategory_id'];
10335            $latestPresetTextbookCategory_textbookCatType = (int)$data['TextbookCategory']['textbook_category_type'];
10336
10337            //Optimize PC /lesson-finish page
10338            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
10339            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
10340                $lessonOnairLatestDataFlg = true;
10341                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
10342                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
10343            } else {
10344                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userId, $teacherId);
10345                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
10346                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
10347                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
10348                }
10349            }
10350
10351            // - initialize empty variable
10352            $isLatestPresetTextbookMadeDuringLastLesson = [];
10353            $latestPresetTextbookParams = [];
10354
10355            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
10356            if ($lessonOnairLatestDataFlg) {
10357                $latestPresetTextbookParams = array (
10358                    'userId' => $userId,
10359                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10360                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
10361                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
10362                );
10363
10364            // - if has lesson onairs log
10365            } else if ($lessonOnairLogsLatestData) {
10366                $latestPresetTextbookParams = array (
10367                    'userId' => $userId,
10368                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
10369                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
10370                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
10371                );
10372
10373            }
10374            
10375            // - if has parameters for fetching latest textbook parameters
10376            if ($latestPresetTextbookParams) {
10377                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
10378            }
10379
10380            // -  check sapuri ID
10381            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
10382                if (isset($lessonOnairLatestDataFlg)) {
10383                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10384                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
10385                    ) {
10386                        $hideTextbookChangeModal = 'true';
10387                    }
10388                } else {
10389                    if (
10390                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
10391                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
10392                    ) {
10393                        $hideTextbookChangeModal = 'true';
10394                    }
10395                }
10396            }
10397
10398            $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
10399
10400            // For enabling next textbook chapter button (if not callan and not ongoing lesson)
10401            if (
10402                $hideTextbookChangeModal == 'false'
10403                && (isset($latestPresetTextbookCategory_textbookCatType) &&  !in_array($latestPresetTextbookCategory_textbookCatType, Configure::read('callan_textbook_type')))
10404                && (isset($onGoingLesson) && $onGoingLesson == false)
10405            ) {
10406                $allTextbookParams = array(
10407                    'category_id' => $latestPresetTextbookConnect_categoryId, 
10408                    'connect_id' => $latestPresetTextbookConnect_id,
10409                    'subcategory_id' => $latestPresetTextbookConnect_subCategoryId
10410                );
10411                
10412                $allTextbookChapters = $this->TextbookConnect->getTextbookPrevAndNextFunction($allTextbookParams);
10413                // if has next textbook chapter, show button 
10414                if (
10415                    is_array($allTextbookChapters) && !is_null($allTextbookChapters) 
10416                    && ($allTextbookChapters['next'] !== '' && !is_null($allTextbookChapters['next']))
10417                ) {
10418                    $enableNextTextbookChapterButton = 'true';
10419                }
10420            }
10421
10422            $this->set('enableNextTextbookChapterButton', $enableNextTextbookChapterButton);
10423
10424            if(!empty($this->sharedUserData['User'])){
10425                // - campaing stamps
10426                $this->getActiveCampaignStampData();
10427            }
10428
10429            $this->set('chatHash', $chatHash);
10430        }
10431
10432        //NJ-33414
10433        $this->UsersDetail->openDBReplica();
10434        $fetchUsersDetail = $this->UsersDetail->find('first', array(
10435            'fields' => array(
10436                'lesson_request_flg'
10437            ),
10438            'conditions' =>  array('user_id' => $this->sharedUserData['User']['id']),
10439            'recursive' => -1
10440        ));
10441        $this->UsersDetail->closeDBReplica();
10442
10443        $lessonRequestFlg = $fetchUsersDetail ? $fetchUsersDetail['UsersDetail']['lesson_request_flg'] : 1;
10444        $this->set('lessonRequestFlg',$lessonRequestFlg);
10445
10446        //-- NJ-44869 skip communication modal
10447        $lessonSystemTroubleFlg = 0;
10448        $hideConnectionModalFlg = 0;
10449
10450        // if (!empty($chatHash)) {
10451        //     $memcached = new myMemcached();
10452        //     $lessonSystemTroubleCache = $memcached->get('lesson_system_trouble_' . $chatHash);
10453        //     $lessonDisconnectionChatHash = $memcached->get('lesson_disconnection_flag_' . $teacherId);
10454            
10455        //     $hideConnectionModalFlg = $memcached->get('hide_connection_modal_flg_'.$teacherId.'-'.$chatHash);
10456
10457        //     if (!empty($lessonSystemTroubleCache)) {
10458        //         $memcached->delete('lesson_system_trouble_' . $chatHash);
10459        //         $lessonSystemTroubleFlg = 1;
10460        //     } elseif (!empty($lessonDisconnectionChatHash) && $lessonDisconnectionChatHash == $chatHash) {
10461        //         $lessonSystemTroubleFlg = 1;
10462        //     }
10463        // }
10464
10465        $this->set('lessonSystemTroubleCache', $lessonSystemTroubleFlg);
10466        $this->set('hideConnectionModalFlg', $hideConnectionModalFlg);
10467    }
10468
10469    /**
10470     * @api {get} /user/waiting/getTeacherReviews getTeacherReviews()
10471     * @apiName getTeacherReviews
10472     * @apiGroup Waiting
10473     * @apiDescription Retrieves the reviews for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reviews data.
10474     *
10475     * @apiBody {String} [teacherId] The ID of the teacher.
10476     * @apiBody {Boolean} [isCounseling] Indicates whether the request is for a counseling teacher.
10477     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10478     * @apiBody {Boolean} [isCustomerSupport] Indicates whether the request is for a customer support teacher.
10479     * @apiBody {Number} [order] The order of the reviews.
10480     * @apiBody {Number} [limit=4] The limit of reviews to retrieve.
10481     * @apiBody {Number} [page=1] The current page number.
10482     * @apiBody {Number} [rate] The rating filter for the reviews.
10483     * @apiBody {String} [textbook_course] The textbook course filter for the reviews.
10484     * @apiBody {String} [textbook_series] The textbook series filter for the reviews.
10485     * @apiBody {String} [textbook_preset] The textbook preset filter for the reviews.
10486     * @apiBody {String} [textbook_favorite] The textbook favorite filter for the reviews.
10487     * @apiBody {Boolean} [load_categories] Indicates whether to load the textbook categories.
10488     * @apiBody {Boolean} [load_paging] Indicates whether to load the paging data.
10489     * 
10490     * @apiSuccess {String} htmlReviews The HTML content for the reviews.
10491     * @apiSuccess {Number} counselorReviewsCount The count of counselor reviews.
10492     * @apiSuccess {String} htmlPaging The HTML content for the paging data.
10493     * @apiSuccess {Object[]} textbookCategories The textbook categories data.
10494     * @apiSuccess {String} textbookCategories.id The ID of the textbook category.
10495     * @apiSuccess {String} textbookCategories.name The name of the textbook category.
10496     * @apiSuccess {String} textbookCategories.image The image URL of the textbook category.
10497     *
10498     * @apiSuccessExample {json} Success-Response:
10499     *     {
10500     *         "htmlReviews": "<div>Reviews HTML</div>",
10501     *         "counselorReviewsCount": 10,
10502     *         "htmlPaging": "<div>Paging HTML</div>",
10503     *         "textbookCategories": [
10504     *             {
10505     *                 "id": "1",
10506     *                 "name": "Category Name",
10507     *                 "image": "http://example.com/image.jpg"
10508     *             },
10509     *             ...
10510     *         ]
10511     *     }
10512     *
10513     * @apiError {String} error Message indicating the error.
10514     *
10515     * @apiErrorExample {json} Error-Response:
10516     *     {
10517     *         "error": "Invalid request."
10518     *     }
10519     * 
10520     * @apiSampleRequest off
10521     */
10522    public function getTeacherReviews() {
10523        $this->autoRender = $this->layout = false;
10524        $get = $this->request->query;
10525
10526        if (isset($get['teacherId']) && !filter_var($get['teacherId'], FILTER_VALIDATE_INT)) {
10527            return json_encode([]);
10528        }
10529
10530        $counselorReviewsCount = 0;
10531        if (isset($get['teacherId']) || isset($get['isCounseling']) || isset($get['isAvatar']) || isset($get['isCustomerSupport'])) {
10532            if (isset($get['order'])) {
10533                $this->Cookie->write('teacherReviewOrder', $get['order'], true, 0);
10534            }
10535            $order = $this->Cookie->read('teacherReviewOrder') ?? 0;
10536            $limit = !empty($get['limit']) && is_numeric($get['limit']) ? (int) $get['limit'] : 4;
10537            $page  = !empty($get['page'])  && is_numeric($get['page'])  ? (int) $get['page']  : 1;
10538            $params = array(
10539                'order' => $order,
10540                'limit' => $limit,
10541                'offset' => ($page - 1) * $limit,
10542                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10543                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10544                'lang' => $this->localizeDir
10545            );
10546
10547            // office teacher
10548            if ( isset($get['isCounseling']) || isset($get['isCustomerSupport']) ) {
10549                myTools::initializeApiTunnel(array('TeachersCounselorReviewsController'));
10550                $teachersReviews = new TeachersCounselorReviewsController();
10551                $teachersReviews->params = $params;
10552                $isCustomerSupport = isset($get['isCustomerSupport']) ? true : false;
10553                $reviews = $teachersReviews->getAllCounselEvaluation($isCustomerSupport);
10554                $counselorReviewsCount = $teachersReviews->getCountAllEvaluation($isCustomerSupport);
10555            } else {
10556                myTools::initializeApiTunnel(array('TeachersReviewsController'));
10557                $teachersReviews = new TeachersReviewsController();
10558                $params['conditions'] = array();
10559                if(isset($get['isAvatar'])) {
10560                    if(!isset($get['load_categories'])) {
10561                        $params['conditions'][] = "UsersClassEvaluation.teacher_id IN (SELECT id FROM teachers WHERE avatar_id = {$get['teacherId']} AND status = 1)";
10562                        $params['conditions'][] = "UsersClassEvaluation.approve_flag = 1";
10563                        $params['conditions'][] = "UsersClassEvaluation.user_comment <> ''";
10564                    }
10565                    $params['isAvatar'] = true;
10566                    $params['avatarTeacherId'] = $get['teacherId'];
10567                } else {
10568                    $params['conditions']['UsersClassEvaluation.teacher_id'] = $get['teacherId'];
10569                }
10570
10571                $params['rate'] = $get['rate'] ?? null;
10572                $params['textbook_course'] = $get['textbook_course'] ?? null;
10573                $params['textbook_series'] = $get['textbook_series'] ?? null;
10574                $params['textbook_preset'] = $get['textbook_preset'] ?? null;
10575                $params['textbook_favorite'] = $get['textbook_favorite'] ?? null;
10576                $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10577
10578
10579                $userTable = new UserTable($this->Auth->user());
10580                $sapuriPlan = $userTable->isStudySapuri();
10581                $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10582                if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10583                    $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10584                } else {
10585                    $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10586                }
10587
10588                if ($userId = $this->Auth->user('id')) {
10589                    $corporateParams = array('user_id' => $userId);
10590                    $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
10591                    
10592                    if ($corporateTextbookControlFlg == 1) {
10593                        $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10594                    }
10595                }
10596
10597                $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10598                $params['build_conditions']['language_id'] = $reviewLanguage[0];
10599                $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10600                
10601                $teachersReviews->params = $params;
10602                $reviews = $teachersReviews->getReviews();
10603
10604                if (isset($get['load_categories'])) {
10605                    $teachersReviews->params['load_favorite'] = true;
10606                    $teachersReviews->params['isLoadCategories'] = true;
10607                    $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10608                }
10609            }
10610            if ($reviews) {
10611                $view = new View($this, false);
10612                $htmlReviews = $view->element('teacherReviews', array('reviews' => $reviews));
10613
10614                if (isset($get['load_paging'])) {
10615                    $commentCount = $this->UsersClassEvaluation->useReplica()->countTeacherReviews($teachersReviews->convertOldParams($params), true);
10616                    $paging = myTools::paging($page, $commentCount, $limit);
10617                    $htmlPaging = $view->element('pager_link_instructor_reviews_ng', ['paging' => $paging, 'order' => $order]);
10618                }
10619            }
10620        }
10621
10622        $returnArr = array();
10623        if (isset($htmlReviews)) {
10624            $returnArr['htmlReviews'] = $htmlReviews;
10625            $returnArr['counselorReviewsCount'] = $counselorReviewsCount;
10626        }
10627        if (isset($htmlPaging)) {
10628            $returnArr['htmlPaging'] = $htmlPaging;
10629        }
10630        if(isset($textbookCategories)) {
10631            $returnArr['textbookCategories'] = $textbookCategories;
10632        }
10633
10634        return json_encode($returnArr);
10635    }
10636
10637    /**
10638     * @api {post} /user/waiting/favoriteTextbookCategoryForReview favoriteTextbookCategoryForReview()
10639     * @apiName favoriteTextbookCategoryForReview
10640     * @apiGroup Waiting
10641     * @apiDescription Retrieves the favorite textbook categories for review for the authenticated user in Native Camp. It returns the favorite textbook categories data.
10642     *
10643     * @apiBody {String} [lang=ja] The language code for the request.
10644     * @apiBody {Boolean} [isAvatar] Indicates whether the request is for an avatar teacher.
10645     * @apiBody {String} [teacherId] The ID of the teacher.
10646     * 
10647     * @apiSuccess {Object[]} favorite The favorite textbook categories data.
10648     * @apiSuccess {String} favorite.id The ID of the textbook category.
10649     * @apiSuccess {String} favorite.name The name of the textbook category.
10650     * @apiSuccess {String} favorite.image The image URL of the textbook category.
10651     *
10652     * @apiSuccessExample {json} Success-Response:
10653     *     {
10654     *         "favorite": [
10655     *             {
10656     *                 "id": "1",
10657     *                 "name": "Category Name",
10658     *                 "image": "http://example.com/image.jpg"
10659     *             },
10660     *             ...
10661     *         ]
10662     *     }
10663     *
10664     * @apiError {String} error Message indicating the error.
10665     *
10666     * @apiErrorExample {json} Error-Response:
10667     *     {
10668     *         "error": "Invalid request."
10669     *     }
10670     * 
10671     * @apiSampleRequest off
10672     */
10673    public function favoriteTextbookCategoryForReview() {
10674        $this->autoRender = false;
10675        $result = [];
10676        if (isset($this->request->data) ) {
10677            $inputs = $this->request->data;
10678            $lang = 'ja';
10679            if (isset($inputs['lang']) && !empty($inputs['lang'])) $lang = $inputs['lang'];
10680            $this->localizeDir = $lang;
10681
10682            myTools::initializeApiTunnel(array('TeachersReviewsController'));
10683            $teachersReviews = new TeachersReviewsController();
10684            $params = array(
10685                'userId' => $this->Auth->user('id') ? $this->Auth->user('id') : '',
10686                'nc_terminal_type' => Configure::read('nc_terminal_type.pc'),
10687                'lang' => $this->localizeDir
10688            );
10689            $params['conditions'] = array();
10690
10691            if( isset($inputs['isAvatar']) && $inputs['isAvatar'] ) {
10692                $params['isAvatar'] = true;
10693                $params['isLoadCategories'] = true;
10694            } else {
10695                $params['conditions']['UsersClassEvaluation.approve_flag'] = 1;
10696                $params['conditions']['UsersClassEvaluation.user_comment <>'] = '';
10697                $params['conditions']['UsersClassEvaluation.teacher_id'] = $inputs['teacherId'];
10698            }
10699            $params['is_sapuri_user'] = $this->isStudySapuriUser ? true : false;
10700
10701            $userTable = new UserTable($this->Auth->user());
10702            $sapuriPlan = $userTable->isStudySapuri();
10703            $sapuriTextbookType = Configure::read('all_sapuri_textbook_category_types');
10704
10705            if ($this->isStudySapuriUser && isset($sapuriTextbookType[$sapuriPlan])) {
10706                $params['textbook_category_type'] = $sapuriTextbookType[$sapuriPlan];
10707            } else {
10708                $params['textbook_category_type_not_in'] = $sapuriTextbookType;
10709            }
10710
10711            if ($userId = $this->Auth->user('id')) {
10712                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl(['user_id' => $userId]);
10713                if ($corporateTextbookControlFlg == 1) {
10714                    $params['textbook_category_type_not_in'] = Configure::read('kids_callan_kids_textbook_category_types');
10715                }
10716            }
10717
10718            $reviewLanguage = $this->CountryCode->getUserLanguageIdForReview($this->localizeDir, true);
10719            $params['build_conditions']['language_id'] = $reviewLanguage[0];
10720            $params['build_conditions']['not_language_ids'] = $reviewLanguage[1] ?? null;
10721            $params['load_favorite'] = true;
10722            $teachersReviews->params = $params;
10723
10724            $textbookCategories = $teachersReviews->getReviewTextbooks($this->sharedUserData['User'], $this->localizeDir);
10725            $result = !empty($textbookCategories) && isset($textbookCategories['favorite']) ? $textbookCategories['favorite'] : [];
10726        }
10727        return json_encode($result);
10728    }
10729
10730    /**
10731     * @api {post} /user/waiting/teacherAvatarStatus teacherAvatarStatus()
10732     * @apiName teacherAvatarStatus
10733     * @apiGroup Waiting
10734     * @apiDescription Retrieves the status of avatar teachers for the authenticated user in Native Camp. It checks the availability of the specified avatar teachers and returns their status.
10735     *
10736     * @apiBody {String[]} avatar_id_array The array of avatar teacher IDs.
10737     * 
10738     * @apiSuccess {Object} result The status of the avatar teachers.
10739     * @apiSuccess {Object} result.avatarId The status data for the avatar teacher.
10740     * @apiSuccess {Boolean} result.avatarId.available Indicates whether the avatar teacher is available.
10741     * @apiSuccess {String} result.avatarId.status The status of the avatar teacher.
10742     *
10743     * @apiSuccessExample {json} Success-Response:
10744     *     {
10745     *         "123": {
10746     *             "available": true,
10747     *             "status": "online"
10748     *         },
10749     *         "456": {
10750     *             "available": false,
10751     *             "status": "offline"
10752     *         }
10753     *     }
10754     *
10755     * @apiError {String} error Message indicating the error.
10756     *
10757     * @apiErrorExample {json} Error-Response:
10758     *     {
10759     *         "error": "Invalid request."
10760     *     }
10761     * 
10762     * @apiSampleRequest off
10763     */
10764    public function teacherAvatarStatus() {
10765        $this->autoRender = $this->layout = false;
10766        $userId = $this->Auth->user('id') ? $this->Auth->user('id') : '';
10767        $post = $this->request->data;
10768        $avatarIdArr = array_flip(Configure::read("default_avatar_detail"));
10769        $result = array();
10770
10771        if(isset($post["avatar_id_array"]) && is_array($post["avatar_id_array"]) ) {
10772            foreach ($post["avatar_id_array"] as $key => $avatarId) {
10773
10774                    $params = array(
10775                        "user_id" => $userId,
10776                        "avatar_id" => $avatarId
10777                    );
10778                    $data = $this->Avatar->availableTeacher($params);
10779                    $result[$avatarId] = $data;
10780
10781
10782            }
10783
10784        }
10785
10786        return json_encode($result);
10787
10788    }
10789
10790    /**
10791     * @api {get} /user/waiting/checkMaintenanceForAlert checkMaintenanceForAlert()
10792     * @apiName checkMaintenanceForAlert
10793     * @apiGroup Waiting
10794     * @apiDescription Checks if there is an upcoming maintenance period and returns an alert message if maintenance is scheduled.
10795     *
10796     * @apiSuccess {Number} is_maintenance Indicates whether maintenance is scheduled (0: No, 1: Yes).
10797     * @apiSuccess {String} message The maintenance alert message.
10798     * @apiSuccess {Number} [timezone_id] The ID of the user's timezone (if applicable).
10799     *
10800     * @apiSuccessExample {json} Success-Response:
10801     *     {
10802     *         "is_maintenance": 1,
10803     *         "message": "2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。",
10804     *         "timezone_id": 1
10805     *     }
10806     *
10807     * @apiError {String} error Message indicating the error.
10808     *
10809     * @apiErrorExample {json} Error-Response:
10810     *     {
10811     *         "error": "Invalid request."
10812     *     }
10813     * 
10814     * @apiSampleRequest off
10815     */
10816    public function checkMaintenanceForAlert() {
10817        $this->autoRender = $this->layout = false;
10818        $response = array(
10819            'is_maintenance' => 0,
10820            'message' => __d('waiting','2:00AMより定期メンテナンスを行います。レッスンは、2:00AMに終了しますのでご了承ください。')
10821        );
10822        if (!myTools::checkCompanyIP($_SERVER['REMOTE_ADDR'])) {
10823            $conditions = array(
10824                'is_active' => 1,
10825                'start_date <= DATE_ADD(NOW(), INTERVAL 26 MINUTE)',
10826                'end_date >= NOW()'
10827            );
10828            $maintenanceModel = ClassRegistry::init('Maintenance');
10829            $maintenanceModel->openDBReplica();
10830            $maintenance = $maintenanceModel->find('first',array(
10831                'conditions' => $conditions
10832            ));
10833            $maintenanceModel->closeDBReplica();
10834            if ($maintenance) {
10835                $response['is_maintenance'] = 1;
10836                # maintenance time on user side
10837                if ($this->sharedUserData['User']['timezone_id']) {
10838                    $response['timezone_id'] = $this->sharedUserData['User']['timezone_id'];
10839                    $timezones = $this->Timezone->getFormattedRecruitTimezones();
10840                    $userTimeZoneData = $timezones[$this->sharedUserData['User']['timezone_id']];
10841                    $datetime = date($maintenance['Maintenance']['start_date']); // maintenance time
10842                    $timestamp = strtotime($datetime);
10843                    $fromTime = $timestamp + (($userTimeZoneData['jp_time_diff'] / 60) * 60 * 60);
10844                    $userMaintenanceTime = date("g:iA", $fromTime);
10845                    $uData = $this->Timezone->getTimezoneUserData($this->sharedUserData['User']['timezone_id']);
10846                    $alertMessageTime = $userMaintenanceTime. " (UTC".$uData['Timezone']['utc_offset'].") " .$userTimeZoneData['data-timezone_name'];
10847                    $alertMessage = sprintf(__d('waiting','%s より定期メンテナンスを行います。時間になりましたらレッスンも終了しますのでご了承ください。'), $alertMessageTime);
10848                    $response['message'] = $alertMessage;
10849                }
10850            }
10851        }
10852        echo json_encode($response);
10853    }
10854
10855    private function isAvatar($teacherID=null){
10856        $result = null;
10857        if ($teacherID) {
10858            $get = $this->Teacher->useReplica()->find('first',array(
10859                    'conditions' => array( 'Teacher.id' => $teacherID ),
10860                    'fields' => array(
10861                        'Teacher.id',
10862                        'Teacher.avatar_id',
10863                        'Teacher.avatar_parent_flg',
10864                        'Teacher.avatar_flg'
10865                    ),
10866                    'recursive' => -1
10867                )
10868            );
10869            if ($get) {
10870                // check parent
10871                $avatarParent = isset($get['Teacher']['avatar_parent_flg']) && $get['Teacher']['avatar_parent_flg'] ? $get['Teacher']['avatar_parent_flg'] : 0;
10872                $avatar = isset($get['Teacher']['avatar_flg']) && $get['Teacher']['avatar_flg'] ? $get['Teacher']['avatar_flg'] : 0;
10873                $avatarId = isset($get['Teacher']['avatar_id']) && $get['Teacher']['avatar_id'] ? $get['Teacher']['avatar_id'] : 0;
10874
10875                if ( ( $avatar && $avatarId ) || $avatarParent ) {
10876                    if ( $avatar && $avatarId ) {
10877                        $result = $avatarId;
10878                    }
10879                    if ($avatarParent) {
10880                        $result = $teacherID;
10881                    }
10882                }
10883            }
10884        }
10885        return $result;
10886    }
10887
10888
10889
10890    //Retrieves the latest lesson history for a specific user with counselor teachers in Native Camp. It returns the lesson history data.
10891    public function counselorLatestLessonHistory($userId){
10892
10893        $memcache = new myMemcached();
10894        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
10895
10896        $counselorTeacherId =  Configure::read('default_counselor_detail');
10897        //NC-7984
10898        $lessonHistoryJoins = array(
10899            "use index (user_id)",
10900            array(
10901                'type' => 'LEFT',
10902                'table' => 'users_class_evaluations',
10903                'alias' => 'usersClassEvaluations',
10904                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
10905            ),
10906            array(
10907                'type' => 'LEFT',
10908                'table' => 'textbook_connects',
10909                'alias' => 'TextbookConnect',
10910                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
10911            ),
10912            array(
10913                'type' => 'LEFT',
10914                'table' => 'textbook_categories',
10915                'alias' => 'TextbookCategory',
10916                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
10917            ),
10918            array(
10919                'type' => 'LEFT',
10920                'table' => 'textbook_subcategories',
10921                'alias' => 'TextbookSubategory',
10922                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
10923            ),
10924            array(
10925                'type' => 'LEFT',
10926                'table' => 'textbooks',
10927                'alias' => 'Textbook',
10928                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
10929            ),
10930            array(
10931                'type' => 'LEFT',
10932                'table' => 'teachers',
10933                'alias' => 'Teacher',
10934                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
10935            ),
10936            array(
10937                'type' => 'LEFT',
10938                'table' => 'lesson_track_logs',
10939                'alias' => 'LessonTrackLogs',
10940                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
10941            )
10942        );
10943        $lessonHistoryFields = array(
10944            'LessonOnairsLog.id',
10945            'LessonOnairsLog.start_time',
10946            'LessonOnairsLog.end_time',
10947            'LessonOnairsLog.created', //Lesson Data / time
10948            'LessonOnairsLog.chat_hash',
10949            'LessonOnairsLog.lesson_memo',
10950            'LessonOnairsLog.lesson_memo_disp_flg',
10951            'LessonOnairsLog.connect_id',
10952            'LessonOnairsLog.display_message',
10953            'LessonOnairsLog.teacher_id',
10954            'TextbookConnect.id',
10955            'usersClassEvaluations.rate', //Lesson rate
10956            'TextbookCategory.name',
10957            'TextbookCategory.type_id',
10958            'TextbookSubategory.name',
10959            'Textbook.name',
10960            'Teacher.id',
10961            'LessonTrackLogs.lesson_number'
10962        );
10963        $this->Teacher->openDBReplica();
10964        $subQuery = $this->Teacher->find(
10965            'list',
10966            array(
10967                'fields'     => array('Teacher.id'),
10968                'table'      => 'teachers',
10969                'alias'      => 'Teacher',
10970                'conditions' => array(
10971                    'Teacher.counseling_flg' => 1,
10972                    'Teacher.status' => 1
10973                ),
10974                'recursive' => -1
10975            )
10976        );
10977        $this->Teacher->closeDBReplica();
10978
10979        $lessonHistoryConditions = array(
10980            'LessonOnairsLog.teacher_id IN' => $subQuery,
10981            'LessonOnairsLog.user_id' => $userId,
10982            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
10983        );
10984
10985        // - has localized directory
10986        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
10987            // - get the user's language id
10988            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
10989            if ($langId) {
10990
10991                $lessonHistoryJoins[] = array(
10992                    'type' => 'LEFT',
10993                    'table' => 'global_textbook_categories',
10994                    'alias' => 'GlobalTextbookCategory',
10995                    'conditions' => array(
10996                        'GlobalTextbookCategory.language_id' => $langId,
10997                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
10998                    )
10999                );
11000
11001                $lessonHistoryJoins[] = array(
11002                    'type' => 'LEFT',
11003                    'table' => 'global_textbook_subcategories',
11004                    'alias' => 'GlobalTextbookSubcategory',
11005                    'conditions' => array(
11006                        'GlobalTextbookSubcategory.language_id' => $langId,
11007                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11008                    )
11009                );
11010                $lessonHistoryJoins[] = array(
11011                    'type' => 'LEFT',
11012                    'table' => 'global_textbooks',
11013                    'alias' => 'GlobalTextbook',
11014                    'conditions' => array(
11015                        'GlobalTextbook.language_id' => $langId,
11016                        'GlobalTextbook.textbook_id = Textbook.id'
11017                    )
11018                );
11019                $this->LessonOnairsLog->virtualFields = array(
11020                    'gl_subcateg_name' => 'GlobalTextbookSubcategory.gl_name',
11021                    'gl_name' => 'GlobalTextbook.gl_name'
11022                );
11023                $lessonHistoryFields[] = 'gl_categ_name';
11024                $lessonHistoryFields[] = 'gl_subcateg_name';
11025                $lessonHistoryFields[] = 'gl_name';
11026            }
11027        }
11028
11029        // - get lesson history
11030        $this->LessonOnairsLog->openDBReplica();
11031        $latestLessonHistory = $this->LessonOnairsLog->find(
11032            'all',
11033            array(
11034                'joins' => $lessonHistoryJoins,
11035                'fields' => $lessonHistoryFields,
11036                'conditions' => $lessonHistoryConditions,
11037                'limit' => 10, //int
11038                'order' => 'LessonOnairsLog.start_time DESC'
11039            )
11040        );
11041        $this->LessonOnairsLog->closeDBReplica();
11042
11043        $this->set('lessonHistory', $latestLessonHistory);
11044        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11045        //NC-7984
11046    }
11047
11048
11049    //Retrieves the latest lesson history for a specific avatar teacher and user in Native Camp. It returns the lesson history data.
11050    public function avatarLatestLessonHistory($userId, $teacherId){
11051        $memcache = new myMemcached();
11052        $textbookNamesCachedArr = $memcache->get(Configure::read('textbook_names_cache_key'));
11053        //NC-7984
11054        $lessonHistoryJoins = array(
11055            "use index (user_id)",
11056            array(
11057                'type' => 'LEFT',
11058                'table' => 'users_class_evaluations',
11059                'alias' => 'usersClassEvaluations',
11060                'conditions' => array('usersClassEvaluations.chat_hash = LessonOnairsLog.chat_hash')
11061            ),
11062            array (
11063                'type' => 'LEFT',
11064                'table' => 'textbook_connects',
11065                'alias' => 'TextbookConnect',
11066                'conditions' => 'LessonOnairsLog.connect_id = TextbookConnect.id'
11067            ),
11068            array(
11069                'type' => 'LEFT',
11070                'table' => 'textbook_categories',
11071                'alias' => 'TextbookCategory',
11072                'conditions' => 'TextbookConnect.category_id = TextbookCategory.id'
11073            ),
11074            array(
11075                'type' => 'LEFT',
11076                'table' => 'textbook_subcategories',
11077                'alias' => 'TextbookSubategory',
11078                'conditions' => 'TextbookConnect.subcategory_id = TextbookSubategory.id'
11079            ),
11080            array(
11081                'type' => 'LEFT',
11082                'table' => 'textbooks',
11083                'alias' => 'Textbook',
11084                'conditions' => 'Textbook.id = TextbookConnect.textbook_id'
11085            ),
11086            array(
11087                'type' => 'LEFT',
11088                'table' => 'teachers',
11089                'alias' => 'Teacher',
11090                'conditions' => 'LessonOnairsLog.teacher_id = Teacher.id'
11091            ),
11092            array(
11093                'type' => 'LEFT',
11094                'table' => 'lesson_track_logs',
11095                'alias' => 'LessonTrackLogs',
11096                'conditions' => 'LessonTrackLogs.chat_hash = LessonOnairsLog.chat_hash'
11097            )
11098        );
11099        $lessonHistoryFields = array(
11100            'LessonOnairsLog.id',
11101            'LessonOnairsLog.start_time',
11102            'LessonOnairsLog.end_time',
11103            'LessonOnairsLog.created', //Lesson Data / time
11104            'LessonOnairsLog.chat_hash',
11105            'LessonOnairsLog.lesson_memo',
11106            'LessonOnairsLog.lesson_memo_disp_flg',
11107            'LessonOnairsLog.connect_id',
11108            'LessonOnairsLog.display_message',
11109            'TextbookConnect.id',
11110            'usersClassEvaluations.rate', //Lesson rate
11111            'TextbookCategory.name',
11112            'TextbookCategory.type_id',
11113            'TextbookSubategory.name',
11114            'Textbook.name',
11115            'Teacher.id',
11116            'LessonTrackLogs.lesson_number'
11117        );
11118        $this->Teacher->openDBReplica();
11119        $subQuery = $this->Teacher->find(
11120            'list',
11121            array(
11122                'fields'     => array('Teacher.id'),
11123                'table'      => 'teachers',
11124                'alias'      => 'Teacher',
11125                'conditions' => array(
11126                    "(Teacher.avatar_flg = 1 AND Teacher.counseling_flg = 0 AND Teacher.status = 1 AND Teacher.avatar_id = {$teacherId}) || (Teacher.avatar_parent_flg = 1 AND Teacher.id = {$teacherId})"
11127                ),
11128                'recursive' => -1
11129            )
11130        );
11131        $this->Teacher->closeDBReplica();
11132
11133        $lessonHistoryConditions = array(
11134            'LessonOnairsLog.user_id' => $userId,
11135            'LessonOnairsLog.delete_flg <> ' => $this->LessonOnairsLog::DELETED
11136        );
11137
11138        if(is_array($subQuery) && !empty($subQuery)){
11139            $lessonHistoryConditions['LessonOnairsLog.teacher_id IN'] = $subQuery;
11140        }
11141
11142        // - has localized directory
11143        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11144            // - get the user's language id
11145            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11146            if ($langId) {
11147
11148                $lessonHistoryJoins[] = array(
11149                    'type' => 'LEFT',
11150                    'table' => 'global_textbook_categories',
11151                    'alias' => 'GlobalTextbookCategory',
11152                    'conditions' => array(
11153                        'GlobalTextbookCategory.language_id' => $langId,
11154                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11155                    )
11156                );
11157
11158                $lessonHistoryJoins[] = array(
11159                    'type' => 'LEFT',
11160                    'table' => 'global_textbook_subcategories',
11161                    'alias' => 'GlobalTextbookSubcategory',
11162                    'conditions' => array(
11163                        'GlobalTextbookSubcategory.language_id' => $langId,
11164                        'GlobalTextbookSubcategory.textbook_subcategory_id = TextbookSubategory.id'
11165                    )
11166                );
11167                $lessonHistoryJoins[] = array(
11168                    'type' => 'LEFT',
11169                    'table' => 'global_textbooks',
11170                    'alias' => 'GlobalTextbook',
11171                    'conditions' => array(
11172                        'GlobalTextbook.language_id' => $langId,
11173                        'GlobalTextbook.textbook_id = Textbook.id'
11174                    )
11175                );
11176
11177                $lessonHistoryFields[] = 'GlobalTextbookCategory.gl_name';
11178                $lessonHistoryFields[] = 'GlobalTextbookSubcategory.gl_name';
11179                $lessonHistoryFields[] = 'GlobalTextbook.gl_name';
11180            }
11181        }
11182
11183        // - get lesson history
11184        $this->LessonOnairsLog->openDBReplica();
11185        $latestLessonHistory = $this->LessonOnairsLog->find(
11186            'all',
11187            array(
11188                'joins' => $lessonHistoryJoins,
11189                'fields' => $lessonHistoryFields,
11190                'conditions' => $lessonHistoryConditions,
11191                'limit' => 10, //int
11192                'order' => 'LessonOnairsLog.start_time DESC'
11193            )
11194        );
11195        $this->LessonOnairsLog->closeDBReplica();
11196
11197        $this->set('lessonHistory', $latestLessonHistory);
11198        $this->set('textbookNamesCachedArr', $textbookNamesCachedArr);
11199        //NC-7984
11200    }
11201
11202    private function userAvailPopularTeacher($params=array()){
11203        $result = false;
11204        if ( isset($params['user_id']) && isset($params['avatar_id']) ) {
11205            $userId = $params['user_id'];
11206            $avatarId = $params['avatar_id'];
11207
11208            $getTeacherAvatars = $this->Teacher->getAvatarTeacherId($params);
11209            if ($getTeacherAvatars) {
11210                $disconCancel = Configure::read('accounting.disconnection_cancellation_lesson_finish');
11211                // - check if has db replica
11212                $this->LessonOnairsLog->openDBReplica();
11213                $countLessons = $this->LessonOnairsLog->find('count', array(
11214                        'conditions' => array(
11215                        'LessonOnairsLog.user_id' => $userId,
11216                        'LessonOnairsLog.teacher_id' => array_values($getTeacherAvatars),
11217                        'LessonOnairsLog.start_time IS NOT NULL',
11218                        'LessonOnairsLog.end_time IS NOT NULL',
11219                        'LessonOnairsLog.connect_id IS NOT NULL',
11220                        'LessonOnairsLog.lesson_finish' => 1
11221                    ),
11222                    'recursive' => -1
11223                ));
11224                $this->LessonOnairsLog->closeDBReplica();
11225
11226                if ($countLessons < 1) {
11227                    $result = true;
11228                }
11229
11230            }
11231
11232        }
11233        return $result;
11234    }
11235
11236
11237    //NC-8728 check if user is valid for Study Sapuri Business English Daily textbooks
11238    private function userValidForSSBEDT(){
11239        $userValidForSSBEDT = false;
11240        if (
11241              (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')) &&
11242              ($this->Auth->loggedIn() && $this->Auth->user('currency_code') == Configure::read('default.user_currency'))
11243        ){
11244            $userValidForSSBEDT = true;
11245        }
11246
11247        return $userValidForSSBEDT;
11248    }
11249
11250    /**
11251     * @api {post} /user/waiting/loadLiveLessonTeacher loadLiveLessonTeacher()
11252     * @apiName loadLiveLessonTeacher
11253     * @apiGroup Waiting
11254     * @apiDescription Retrieves the list of teachers available for live lessons in Native Camp. It checks if the request is an AJAX request and returns the list of live lesson teachers.
11255     *
11256     * @apiBody {Number} [current_page=1] The current page number.
11257     * @apiBody {Number} [limit] The limit of teachers to retrieve.
11258     * @apiBody {String} [local_timezone] The local timezone of the user.
11259     * @apiBody {Boolean} [isGuestViwer] Indicates whether the user is a guest viewer.
11260     * @apiBody {Boolean} [isMobile] Indicates whether the request is from a mobile device.
11261     * @apiBody {String} [template] The template to use for rendering the teacher list.
11262     * @apiBody {String} [token] The API token of the user.
11263     * 
11264     * @apiSuccess {Object[]} liveTeacherList The list of teachers available for live lessons.
11265     * @apiSuccess {String} liveTeacherList.name The teacher's name.
11266     * @apiSuccess {String} liveTeacherList.id The teacher's unique identifier.
11267     * @apiSuccess {String} liveTeacherList.profilePicture URL to the teacher's profile picture.
11268     * @apiSuccess {Boolean} ajaxDisplay Indicates if the request was made via AJAX.
11269     * @apiSuccess {Number} userJpTimeDiffSecond The time difference in seconds between the user's local time and Japan time.
11270     * @apiSuccess {Number} studentLessonPriorityTimeDelayInSeconds The delay in seconds for student lesson priority.
11271     * @apiSuccess {Object} teacherListLiveParameters The parameters for the live teacher list (if applicable).
11272     * @apiSuccess {String} teacherListLiveParameters.user_id The ID of the user.
11273     * @apiSuccess {String} teacherListLiveParameters.user_language The language of the user.
11274     * @apiSuccess {Boolean} teacherListLiveParameters.pc_view Indicates if the view is for PC.
11275     * @apiSuccess {Number} teacherListLiveParameters.page The current page number.
11276     * @apiSuccess {String} teacherListLiveParameters.template The template used for rendering the teacher list.
11277     * @apiSuccess {Boolean} teacherListLiveParameters.mobapp_view Indicates if the view is for mobile app.
11278     * @apiSuccess {Number} teacherListLiveParameters.limit The limit of teachers to retrieve.
11279     * @apiSuccess {Boolean} teacherListLiveParameters.isGuestViwer Indicates if the user is a guest viewer.
11280     * @apiSuccess {Boolean} teacherListLiveParameters.isMobile Indicates if the request is from a mobile device.
11281     *
11282     * @apiSuccessExample {json} Success-Response:
11283     *     {
11284     *         "liveTeacherList": [
11285     *             {
11286     *                 "name": "Teacher Name",
11287     *                 "id": "123456",
11288     *                 "profilePicture": "https://www.nativecamp.net/img/teacher/123456.jpg"
11289     *             },
11290     *             ...
11291     *         ],
11292     *         "ajaxDisplay": true,
11293     *         "userJpTimeDiffSecond": 32400,
11294     *         "studentLessonPriorityTimeDelayInSeconds": 60,
11295     *         "teacherListLiveParameters": {
11296     *             "user_id": "789",
11297     *             "user_language": "en",
11298     *             "pc_view": true,
11299     *             "page": 1,
11300     *             "template": "pc_usage",
11301     *             "mobapp_view": false,
11302     *             "limit": 10,
11303     *             "isGuestViwer": false,
11304     *             "isMobile": false
11305     *         }
11306     *     }
11307     *
11308     * @apiError {String} error Message indicating the error.
11309     *
11310     * @apiErrorExample {json} Error-Response:
11311     *     {
11312     *         "error": "Invalid request."
11313     *     }
11314     * 
11315     * @apiSampleRequest off
11316     */
11317    public function loadLiveLessonTeacher(){
11318        $data = $this->request->data;
11319        $liveTeacherList = array();
11320        $params = array();
11321        $currentPage = !empty($data['current_page']) ? $data['current_page'] : 1 ;
11322        $limit = isset($data['limit']) ? $data['limit'] : null;
11323        $userJpTimeDiffSecond = !empty($this->timeDiffSecond) ? $this->timeDiffSecond : 0;
11324        $isGuestViwer = !empty($data['isGuestViwer']) ? 1 : 0;
11325
11326        //- if token set
11327        if (!empty($this->request->query['token'])) {
11328            $this->User->openDBReplica();
11329            $this->sharedUserData = $this->User->find('first', [
11330                'conditions' => ['api_token' => $this->request->query['token']],
11331                'recursive' => -1
11332            ]);
11333            $this->User->closeDBReplica();
11334
11335        }
11336
11337        //-- get JP time difference for logout users
11338        if (
11339            (empty($this->sharedUserData['User']) || $isGuestViwer)
11340            && !empty($data['local_timezone'])
11341            && $data['local_timezone'] != 'Asia/Tokyo'
11342        ) {
11343            $localTimezoneName = explode('/', $data['local_timezone']);
11344            if ( !empty($localTimezoneName[1]) ) {
11345                $this->Timezone->openDBReplica();
11346                $jpTimeDiff = $this->Timezone->find('first', array(
11347                    'fields' => 'jp_time_diff',
11348                    'conditions' => array(
11349                        'Timezone.city_eng LIKE ? ' => array($localTimezoneName[1])
11350                    ),
11351                    'recursive' => -1
11352                ));
11353                $this->Timezone->closeDBReplica();
11354                $userJpTimeDiffSecond = !empty($jpTimeDiff['Timezone']['jp_time_diff']) ? ((int)$jpTimeDiff['Timezone']['jp_time_diff'] * 60) : $userJpTimeDiffSecond;
11355            }
11356        }
11357
11358        //-- check if current user can use live lesson
11359        if ( 
11360            $isGuestViwer
11361            || empty($this->sharedUserData['User']) 
11362            || UserTable::canJoinLiveViewing($this->sharedUserData['User'])
11363        ){
11364            //-- set list of params for teacher live lessons
11365            $params = array(
11366                'user_id' => !empty($this->sharedUserData['User']['id']) ? $this->sharedUserData['User']['id'] : null,
11367                'payment_plan_id' => !empty($this->sharedUserData['User']['payment_plan_id']) ? $this->sharedUserData['User']['payment_plan_id'] : null,
11368                'currency_code' => !empty($this->sharedUserData['User']['currency_code']) ? $this->sharedUserData['User']['currency_code'] : null,
11369                'user_language' => isset($this->localizeDir) ? $this->localizeDir : $this->sharedUserData['User']['native_language2'],
11370                'pc_view' => true,
11371                'page' => $currentPage,
11372                'template' => isset($data['template']) ? $data['template'] : '',
11373                'mobapp_view' => isset($data['template']) ? true : false,
11374                'limit' => $limit,
11375                'isGuestViwer' => $isGuestViwer,
11376                'isMobile' => !empty($data['isMobile']) ? 1 : 0, // TODO: Add new key-value pair if it is an SP view or mobileApp
11377            );
11378            // Get list of teachers for live lessons
11379            $liveTeacherList = $this->CommonTeacherStatus->liveTeacherList($params);
11380        }
11381        //-- return blank respond
11382        if ( empty($liveTeacherList) ) {
11383            $this->autoRender = false;
11384            $this->layout = false;
11385            return false;
11386        }
11387        // - pass view parameters
11388        $this->set('ajaxDisplay', true);
11389        $this->set('userJpTimeDiffSecond', $userJpTimeDiffSecond);
11390        $this->set('liveTeacherList', $liveTeacherList);
11391        $this->set('studentLessonPriorityTimeDelayInSeconds', (int)$this->studentLessonPriorityTimeDelayInSeconds);
11392        //-- if guest viwer with SP screen
11393        if ( $isGuestViwer && !empty($data['isMobile']) ) {
11394            $this->set('teacherListLiveParameters', $params); //TODO:: Pass the params to live_teacher_banner only in SP_side
11395            return $this->render('/Elements/mobile/live_teacher_banner_list');
11396        }
11397
11398        // - if usage template
11399        if (isset($data['template']) && in_array($data['template'], ["pc_usage", "mobapp_usage"])) {
11400            return $this->render('/Elements/live_teacher_pc_usage_list');
11401
11402        // - else use default
11403        } else {
11404            return $this->render('/Elements/live_teacher_banner_list');
11405        }
11406    }
11407
11408    /**
11409     * @api {get} /user/waiting/sms_questionnaire sms_questionnaire()
11410     * @apiName sms_questionnaire
11411     * @apiGroup Waiting
11412     * @apiDescription Redirects the user to the SMS questionnaire page for a specific teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11413     *
11414     * @apiBody {String} teacherId The ID of the teacher.
11415     * 
11416     * @apiSuccess {String} redirect The URL to redirect to.
11417     *
11418     * @apiSuccessExample {view} Redirect-Response:
11419     *  - Redirects to the /account/sms_questionnaire page.
11420     *
11421     * @apiError {String} error Message indicating the error.
11422     *
11423     * @apiErrorExample {json} Error-Response:
11424     *     {
11425     *         "error": "Invalid request."
11426     *     }
11427     * 
11428     * @apiSampleRequest off
11429     */
11430    public function sms_questionnaire($teacherId = null) {
11431        if (is_null($teacherId)) {
11432            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11433        }
11434        $data = array(
11435            'origin_url' => '/waiting/detail/'.$teacherId,
11436            'success_url' => '/waiting/detail/'.$teacherId
11437        );        
11438        $this->Session->write($data);
11439        return $this->redirect('/account/sms_questionnaire');
11440    }
11441    
11442    /**
11443     * @api {get} /user/waiting/avatar_sms_questionnaire avatar_sms_questionnaire()
11444     * @apiName avatar_sms_questionnaire
11445     * @apiGroup Waiting
11446     * @apiDescription Redirects the user to the SMS questionnaire page for a specific avatar teacher in Native Camp. It sets the origin and success URLs in the session and redirects to the SMS questionnaire page.
11447     *
11448     * @apiBody {String} teacherId The ID of the avatar teacher.
11449     * 
11450     * @apiSuccess {String} redirect The URL to redirect to.
11451     *
11452     * @apiSuccessExample {view} Redirect-Response:
11453     *  - Redirects to the /account/sms_questionnaire page.
11454     *
11455     * @apiError {String} error Message indicating the error.
11456     *
11457     * @apiErrorExample {json} Error-Response:
11458     *     {
11459     *         "error": "Invalid request."
11460     *     }
11461     * 
11462     * @apiSampleRequest off
11463     */
11464    public function avatar_sms_questionnaire($teacherId = null) {
11465        if (is_null($teacherId)) {
11466            return $this->redirect(myTools::getUrl() . '/user/waiting', 301);
11467        }
11468        $data = array(
11469            'origin_url' => '/avatar_detail/'.$teacherId,
11470            'success_url' => '/avatar_detail/'.$teacherId
11471        );        
11472        $this->Session->write($data);
11473        return $this->redirect('/account/sms_questionnaire');
11474    }
11475
11476    /**
11477     * @api {post} /user/waiting/checkCounselorTeacherButtonStatus checkCounselorTeacherButtonStatus()
11478     * @apiName checkCounselorTeacherButtonStatus
11479     * @apiGroup Waiting
11480     * @apiDescription Checks the status of the counselor teacher button for the authenticated user in Native Camp. It returns the availability of the counselor teacher, whether the daily limit is exceeded, and other related data.
11481     *
11482     * @apiBody {Boolean} [dev_test] Indicates whether the request is for development testing.
11483     * @apiBody {Boolean} [customer_support_flg] Indicates whether customer support is enabled.
11484     * 
11485     * @apiSuccess {String} available_teacher The ID of the available teacher.
11486     * @apiSuccess {Boolean} exceed_daily_limit Indicates whether the daily limit is exceeded.
11487     * @apiSuccess {Number} res The result status (0: Not available, 1: Available, 3: Logout).
11488     * @apiSuccess {String} chat_hash The chat hash.
11489     * @apiSuccess {Number} Membership type for checking if the user is not free trial
11490     *
11491     * @apiSuccessExample {json} Success-Response:
11492     *     {
11493     *         "available_teacher": "123",
11494     *         "exceed_daily_limit": 0,
11495     *         "res": 1,
11496     *         "chat_hash": "example_chat_hash",
11497     *            "membership_type": "example_membership_type"
11498     *     }
11499     *
11500     * @apiError {String} error Message indicating the error.
11501     *
11502     * @apiErrorExample {json} Error-Response:
11503     *     {
11504     *         "error": "Invalid request."
11505     *     }
11506     * 
11507     * @apiSampleRequest off
11508     */
11509    public function checkCounselorTeacherButtonStatus() {
11510        $this->autoRender = false;
11511        $this->layout = false;
11512        
11513        $result = 0; // Not available
11514        $devTest = isset($this->request->query['dev_test']) && $this->request->query['dev_test'] ? 1 : 0;
11515
11516        if (isset($this->request->data['customer_support_flg']) && ( $this->request->data['customer_support_flg'] == 'false' || $this->request->data['customer_support_flg'] == false )) {
11517            $customer_support_flg = 0;
11518        }else{
11519            $customer_support_flg = 1;
11520        }
11521        $userId = $this->Auth->user('id');
11522        $teacherId = 0;
11523        $exceedDailyLimit = false;
11524        $chat_hash = null;
11525        $userData = $this->sharedUserData['User'];
11526        if ( $this->request->is('ajax') || $devTest ) {
11527            if ( $userId ) {
11528                $counselorParams = array(
11529                    'user_id' => $userId,
11530                    'user_data' => $userData,
11531                    'customer_support_flg' => $customer_support_flg
11532                );
11533                $data = $this->LessonOnair->checkCounselorTeacherButtonStatus($counselorParams);
11534                $dataObj = json_decode($data,true);
11535                $teacherId = $dataObj['available_teacher'] ?? '';
11536                $exceedDailyLimit = $dataObj['exceed_daily_limit'] ?? '';
11537                $result = $dataObj['res'] ?? '';
11538                $chat_hash = $dataObj['chat_hash'] ?? '';
11539            } else {
11540                $result = 3; // logout
11541            }
11542        }
11543
11544        if($userId){
11545            $csList = ($customer_support_flg == 1) ? $this->Teacher->getCustomerSupportTeachers() : $this->Teacher->getCounselorTeachers();
11546            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, ($customer_support_flg == 1) ?  $csList['customerSupportId'] : $csList['counselorId']);
11547            if($csExceedLimitCheck){
11548                $exceedDailyLimit = true;
11549            }
11550        }
11551
11552        return json_encode(
11553            array(
11554                'available_teacher' => $teacherId,
11555                'exceed_daily_limit' => ( $exceedDailyLimit ) ? 1 : 0,
11556                'res' => $result,
11557                'chat_hash' => $chat_hash,
11558                'membership_type' => $this->userMembershipType
11559            )
11560        );
11561    }
11562
11563    /**
11564     * @api {get} /user/emergency emergencyLesson()
11565     * @apiName emergencyLesson
11566     * @apiGroup Waiting
11567     * @apiDescription Retrieves the emergency lesson data for the authenticated user in Native Camp. It checks if the user is a Study Sapuri TOS user and returns the preset textbook data.
11568     * 
11569     * @apiSuccess {Object} preset The preset textbook data.
11570     * @apiSuccess {String} preset.textbook_connect_id The ID of the textbook connect.
11571     * @apiSuccess {String} preset.textbook_type The type of the textbook.
11572     * @apiSuccess {Object} searchData The saved search condition data.
11573     * @apiSuccess {String} textbookConnectId The ID of the textbook connect.
11574     * @apiSuccess {String} textbookCategoryTypeId The type ID of the textbook category.
11575     *
11576     * @apiSuccessExample {json} Success-Response
11577     *     {
11578     *         "preset": {
11579     *             "textbook_connect_id": "123",
11580     *             "textbook_type": "1"
11581     *         },
11582     *         "searchData": {...},
11583     *         "textbookConnectId": "123",
11584     *         "textbookCategoryTypeId": "1"
11585     *     }
11586     *
11587     * @apiError {String} error Message indicating the error.
11588     *
11589     * @apiErrorExample {json} Error-Response:
11590     *     {
11591     *         "error": "Not Found"
11592     *     }
11593     * 
11594     * @apiSampleRequest off
11595     */
11596    public function emergencyLesson() {
11597        if (!$this->isStudySapuriTosUser) {
11598            throw new NotFoundException();
11599        }
11600
11601        $presetParams = array("user_id" => $this->Auth->user('id'));
11602        $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
11603        if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
11604                # for preset
11605                $presetParams['connect_id'] = $preset_data['preset_connect_id'];
11606                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11607        } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
11608                # use last viewed textbook if no preset data.
11609                $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
11610                $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
11611        }
11612        
11613        # fetch preset 
11614        $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11615        if(!$preset) {
11616                unset($presetParams['connect_id']);
11617                unset($presetParams['last_opened_date']);
11618                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
11619        }
11620
11621        // NC-7228 set series id from saved search condition
11622        $searchData = $this->Cookie->read('searchData');
11623        $this->set('preset', $preset);
11624        $this->set('searchData', $searchData);
11625        $this->set('textbookConnectId', $preset['textbook_connect_id']);
11626        $this->set('textbookCategoryTypeId', $preset['textbook_type']);
11627        return $this->render('/Waiting/emergency_lesson');
11628    }
11629    
11630    /**
11631     * @api {post} /user/waiting/teacherBadgeList teacherBadgeList()
11632     * @apiName teacherBadgeList
11633     * @apiGroup Waiting
11634     * @apiDescription Retrieves the badge list for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11635     *
11636     * @apiBody {String} teacherId The ID of the teacher.
11637     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11638     * 
11639     * @apiSuccess {Object[]} series The series data.
11640     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11641     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11642     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11643     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11644     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11645     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11646     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11647     * @apiSuccess {Object} teacherTbRatings The teacher textbook ratings data.
11648     * @apiSuccess {Number} teacherTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11649     * @apiSuccess {Object[]} titleThresholdTextbookList The title threshold textbook list data.
11650     * @apiSuccess {String} titleThresholdTextbookList.title The title of the threshold.
11651     * @apiSuccess {Number} titleThresholdTextbookList.threshold The threshold value.
11652     *
11653     * @apiSuccessExample {json} Success-Response:
11654     *     {
11655     *         "series": [
11656     *             {
11657     *                 "TextbookCategory": {
11658     *                     "name": "Category Name",
11659     *                     "id": "1",
11660     *                     "type_id": "2",
11661     *                     "image_big_url": "http://example.com/image.jpg"
11662     *                 },
11663     *                 "TeacherBadge": {
11664     *                     "textbook_category_id": "1",
11665     *                     "badge_flg": true
11666     *                 },
11667     *                 "gl_name": "Global Category Name"
11668     *             }
11669     *         ],
11670     *         "teacherTbRatings": {
11671     *             "1": {
11672     *                 "teacher_textbook_rating": 4.5
11673     *             }
11674     *         },
11675     *         "titleThresholdTextbookList": [
11676     *             {
11677     *                 "title": "Expert",
11678     *                 "threshold": 100
11679     *             },
11680     *             {
11681     *                 "title": "Master",
11682     *                 "threshold": 200
11683     *             }
11684     *         ]
11685     *     }
11686     *
11687     * @apiError {String} error Message indicating the error.
11688     *
11689     * @apiErrorExample {json} Error-Response:
11690     *     {
11691     *         "error": "Invalid request."
11692     *     }
11693     * 
11694     * @apiSampleRequest off
11695     */
11696    public function teacherBadgeList() {
11697        $this->layout = "";
11698        if (!$this->request->is('ajax')) { return ; }
11699        
11700        $teacherId = $this->request->data['teacherId'];
11701        if (empty($teacherId)) { return ; }
11702
11703        $fieldArr = array(
11704            'TextbookCategory.name',
11705            'TextbookCategory.id',
11706            'TextbookCategory.type_id',
11707            'TeacherBadge.textbook_category_id',
11708            'TeacherBadge.badge_flg',
11709            'TextbookCategory.type_id',
11710            'TextbookCategory.image_big_url'
11711        );
11712        $joinArr = array(
11713            array(
11714                'table' => 'teacher_badges',
11715                'alias' => 'TeacherBadge',
11716                'type' => 'INNER',
11717                'conditions' => array(
11718                    'TeacherBadge.textbook_category_id = TextbookCategory.id',
11719                    'TeacherBadge.teacher_id' => $teacherId)
11720            )
11721        );
11722
11723        // if the user's language is zh-tw, display chinese textbook badge name
11724        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11725            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11726            if($langId){
11727                $joinArr[] = array(
11728                    'type' => 'LEFT',
11729                    'table' => 'global_textbook_categories',
11730                    'alias' => 'GlobalTextbookCategory',
11731                    'conditions' => array(
11732                        'GlobalTextbookCategory.language_id' => $langId,
11733                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11734                    )
11735                );
11736                $this->TextbookCategory->virtualFields = array(
11737                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11738                );
11739                $fieldArr[] = 'gl_name';
11740            }
11741        }
11742
11743        $conArr = array(
11744            'TextbookCategory.status' => 1,
11745            'TextbookCategory.type_id' => 2
11746        );
11747
11748        # get studydapuri textbooks
11749        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11750        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11751            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11752            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11753        } elseif ($this->isStudySapuriTosUser) {
11754            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11755        } else {
11756            $exCat = Configure::read('all_sapuri_textbook_category_types');
11757            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11758        }
11759
11760        // NJ-5836
11761        $displayRestrictionParams = array(
11762            'lang' => $this->localizeDir
11763        );
11764
11765        // get display restriction setting
11766        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11767
11768        // NJ-5836 add condition for display restriction
11769        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11770            // set condition for display restriction
11771            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11772        }
11773
11774        //get series and badge
11775        $series = $this->TextbookCategory->find('all', array(
11776            'fields' => $fieldArr,
11777            'conditions' => $conArr,
11778            'joins' => $joinArr,
11779            'order' => array(
11780                'TextbookCategory.sort' => 'ASC'
11781            )
11782        ));
11783
11784        $this->set('series', $series);            
11785        
11786        $teacherTbRatings = array();
11787        if($series && is_array($series)) {
11788            foreach($series as $key => $books){            
11789                $categoryId = $books['TextbookCategory']['id'];
11790                $params = array(
11791                    'teacher_id' =>  (int) $teacherId,
11792                    'textbook_category_id' => (int) $categoryId,
11793                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11794                );    
11795                $decodeResp = json_decode($this->TeacherTextbookStat->teacherTextbookRating($params));
11796                $teacherTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11797            }
11798        }
11799        $this->set('teacherTbRatings', $teacherTbRatings);
11800
11801        // NJ-17264
11802        $titleThresholdTextbookList = $this->TitleThresholdTeacher->getTitleTresholdPerTextbookCategory(['teacherId' => $teacherId, 'type' => 0]);    
11803
11804        $this->set('titleThresholdTextbookList', $titleThresholdTextbookList);
11805
11806        // new UI
11807        $this->render('teacher_badge_list');
11808        if( isset($this->request->data['sp']) && $this->request->data['sp'] ) {
11809            $this->render('sp_teacher_badge_list');
11810        }
11811    }
11812
11813    /**
11814     * @api {post} /user/waiting/avatarBadgeList avatarBadgeList()
11815     * @apiName avatarBadgeList
11816     * @apiGroup Waiting
11817     * @apiDescription Retrieves the badge list for a specific avatar teacher in Native Camp. It checks if the request is an AJAX request and returns the badge list data.
11818     *
11819     * @apiBody {String} teacher_avatar_id The ID of the avatar teacher.
11820     * @apiBody {Boolean} [sp] Indicates whether the request is from SP.
11821     * 
11822     * @apiSuccess {Object[]} series The series data.
11823     * @apiSuccess {String} series.TextbookCategory.name The name of the textbook category.
11824     * @apiSuccess {String} series.TextbookCategory.id The ID of the textbook category.
11825     * @apiSuccess {String} series.TextbookCategory.type_id The type ID of the textbook category.
11826     * @apiSuccess {String} series.TeacherBadge.textbook_category_id The textbook category ID of the teacher badge.
11827     * @apiSuccess {Boolean} series.TeacherBadge.badge_flg The badge flag of the teacher badge.
11828     * @apiSuccess {String} series.TextbookCategory.image_big_url The image URL of the textbook category.
11829     * @apiSuccess {String} [series.gl_name] The global name of the textbook category (if available).
11830     * @apiSuccess {Object} avatarTbRatings The avatar textbook ratings data.
11831     * @apiSuccess {Number} avatarTbRatings.teacher_textbook_rating The rating of the teacher for the textbook category.
11832     *
11833     * @apiSuccessExample {json} Success-Response:
11834     *     {
11835     *         "series": [
11836     *             {
11837     *                 "TextbookCategory": {
11838     *                     "name": "Category Name",
11839     *                     "id": "1",
11840     *                     "type_id": "2",
11841     *                     "image_big_url": "http://example.com/image.jpg"
11842     *                 },
11843     *                 "TeacherBadge": {
11844     *                     "textbook_category_id": "1",
11845     *                     "badge_flg": true
11846     *                 },
11847     *                 "gl_name": "Global Category Name"
11848     *             }
11849     *         ],
11850     *         "avatarTbRatings": {
11851     *             "1": {
11852     *                 "teacher_textbook_rating": 4.5
11853     *             }
11854     *         }
11855     *     }
11856     *
11857     * @apiError {String} error Message indicating the error.
11858     *
11859     * @apiErrorExample {json} Error-Response:
11860     *     {
11861     *         "error": "Invalid request."
11862     *     }
11863     * 
11864     * @apiSampleRequest off
11865     */
11866    public function avatarBadgeList() {
11867        $this->layout = "";
11868
11869        if (!$this->request->is('ajax')) { return; }
11870        
11871        $avatarId = Sanitize::escape($this->request->data['teacher_avatar_id']);
11872
11873        if (empty($avatarId)) { return; }
11874
11875        $fieldArr = array(
11876            'TextbookCategory.name',
11877            'TextbookCategory.id',
11878            'TextbookCategory.type_id',
11879            'TeacherBadge.textbook_category_id',
11880            'TeacherBadge.badge_flg',
11881            'TextbookCategory.type_id',
11882            'TextbookCategory.image_big_url'
11883        );
11884        $joinArr = array(
11885            array(
11886                'table' => 'teacher_badges',
11887                'alias' => 'TeacherBadge',
11888                'type' => 'INNER',
11889                'conditions' => array('TeacherBadge.textbook_category_id = TextbookCategory.id', 'TeacherBadge.teacher_id' => $avatarId)
11890            )
11891        );
11892
11893        // if the user's language is zh-tw, display chinese textbook badge name
11894        if(isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))){
11895            $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
11896            if($langId){
11897                $joinArr[] = array(
11898                    'type' => 'LEFT',
11899                    'table' => 'global_textbook_categories',
11900                    'alias' => 'GlobalTextbookCategory',
11901                    'conditions' => array(
11902                        'GlobalTextbookCategory.language_id' => $langId,
11903                        'GlobalTextbookCategory.textbook_category_id = TextbookCategory.id'
11904                    )
11905                );
11906                $this->TextbookCategory->virtualFields = array(
11907                    'gl_name' => 'GlobalTextbookCategory.gl_name'
11908                );
11909                $fieldArr[] = 'gl_name';
11910            }
11911        }
11912
11913        $conArr = array(
11914            'TextbookCategory.status' => 1,
11915            'TextbookCategory.type_id' => 2
11916        );
11917
11918        # get studydapuri textbooks
11919        $studysapuriType = Configure::read('studysapuri_textbook_category_types');
11920        if ( $this->studySapuriId && isset($this->sharedUserData['User']['payment_plan_id']) ) {
11921            $plan = myTools::studySapuriContractPlan($this->sharedUserData['User']['payment_plan_id']);
11922            $conArr['TextbookCategory.textbook_category_type'] = $studysapuriType[$plan];
11923        } elseif ($this->isStudySapuriTosUser) {
11924            $conArr['TextbookCategory.textbook_category_type'] = Configure::read('stasapu_tos_textbook_category_type');
11925        } else {
11926            $exCat = Configure::read('all_sapuri_textbook_category_types');
11927            $conArr['NOT'] = array('TextbookCategory.textbook_category_type' => $exCat);
11928        }
11929
11930        // NJ-5836
11931        $displayRestrictionParams = array(
11932            'lang' => $this->localizeDir
11933        );
11934
11935        // get display restriction setting
11936        $displayRestriction = $this->TextbookCategory->getDisplayRestrictionSettings($displayRestrictionParams);
11937
11938        // NJ-5836 add condition for display restriction
11939        if(isset($displayRestriction['field']) && $displayRestriction['field']){
11940            // set condition for display restriction
11941            $conArr['TextbookCategory.'.$displayRestriction['field']] = 1;
11942        }
11943
11944        //get series and badge
11945        $series = $this->TextbookCategory->find('all', array(
11946            'fields' => $fieldArr,
11947            'conditions' => $conArr,
11948            'joins' => $joinArr,
11949            'order' => array(
11950                'TextbookCategory.sort' => 'ASC'
11951            )
11952        ));
11953
11954        $this->set('series', $series);
11955
11956        $avatarTbRatings = array();
11957        if($series && is_array($series)) {
11958            foreach($series as $key => $books){            
11959                $categoryId = $books['TextbookCategory']['id'];
11960                $params = array(
11961                    'avatar_id' => $avatarId,
11962                    'textbook_category_id' => (int) $categoryId,
11963                    'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
11964                );    
11965                $decodeResp = json_decode($this->TeacherTextbookStat->avatarTextbookRating($params));
11966                $avatarTbRatings[$categoryId] = $decodeResp->teacher_textbook_rating;
11967            }
11968        }
11969        $this->set('avatarTbRatings', $avatarTbRatings);
11970        
11971        if(isset($this->request->data['sp']) && $this->request->data['sp']) {
11972            $this->set('avatar_sp', 1);
11973            $this->render('sp_teacher_badge_list');
11974        }
11975
11976    }    
11977
11978    /**
11979     * @api {post} /user/waiting/teacherOccupation teacherOccupation()
11980     * @apiName teacherOccupation
11981     * @apiGroup Waiting
11982     * @apiDescription Retrieves the occupation history of a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the teacher occupation data.
11983     *
11984     * @apiBody {String} teacherId The ID of the teacher.
11985     * 
11986     * @apiSuccess {Object[]} teacherOccupation The teacher occupation data.
11987     * @apiSuccess {String} teacherOccupation.id The ID of the occupation detail.
11988     * @apiSuccess {String} teacherOccupation.teacher_id The ID of the teacher.
11989     * @apiSuccess {String} teacherOccupation.occupation The occupation of the teacher.
11990     * @apiSuccess {String} teacherOccupation.start_date The start date of the occupation.
11991     * @apiSuccess {String} teacherOccupation.end_date The end date of the occupation.
11992     * @apiSuccess {String} lang The language code for the page.
11993     *
11994     * @apiSuccessExample {json} Success-Response:
11995     *     {
11996     *         "teacherOccupation": [
11997     *             {
11998     *                 "id": "1",
11999     *                 "teacher_id": "123",
12000     *                 "occupation": "Software Engineer",
12001     *                 "start_date": "2020-01-01",
12002     *                 "end_date": "2021-01-01"
12003     *             },
12004     *             {
12005     *                 "id": "2",
12006     *                 "teacher_id": "123",
12007     *                 "occupation": "Project Manager",
12008     *                 "start_date": "2021-02-01",
12009     *                 "end_date": "2022-01-01"
12010     *             }
12011     *         ],
12012     *         "lang": "en"
12013     *     }
12014     *
12015     * @apiError {String} error Message indicating the error.
12016     *
12017     * @apiErrorExample {json} Error-Response:
12018     *     {
12019     *         "error": "Invalid request."
12020     *     }
12021     * 
12022     * @apiSampleRequest off
12023     */
12024    public function teacherOccupation() {
12025        $this->layout = "";
12026        if (!$this->request->is('ajax')) { return ; }
12027        
12028        $teacherId = $this->request->data['teacherId'];
12029        if (empty($teacherId)) { return ; }
12030
12031        //NC-9215 get teacher occupation history
12032        $teacherOccupation = ClassRegistry::init('TeacherOccupationDetail')->getTeacherOccupationDetails($teacherId);
12033        $this->set('teacherOccupation', $teacherOccupation);
12034        $lang = isset($this->localizeDir) ? $this->localizeDir : Configure::read('default.user_language');
12035        $this->set('lang', $lang);        
12036
12037        $this->render('teacher_occupation');
12038    }
12039
12040     //only used in this class controller
12041     //Retrieves the features of a specific teacher in Native Camp. It checks if the request is an AJAX request or if it is called from SP, and returns the teacher features data.
12042    public function teacherFeatures($sp = false, $teacherId = null) {
12043        $this->autoRender = false;
12044        $this->layout = false;
12045        if ($this->request->is('ajax') || $sp) {
12046            $teacherId = $this->request->data['teacherId'] ?? $teacherId;
12047            if (empty($teacherId)) { return ; }
12048    
12049            $feature = $this->TeacherFeature->find('first', array(
12050                'conditions' =>  array(
12051                    'TeacherFeature.teacher_id' => $teacherId
12052                )
12053            ));
12054            return json_encode(isset($feature['TeacherFeature']) ? $feature['TeacherFeature'] : array());
12055        } return;
12056    }
12057
12058    /**
12059     * @api {post} /user/waiting/getSelfReviews getSelfReviews()
12060     * @apiName getSelfReviews
12061     * @apiGroup Waiting
12062     * @apiDescription Retrieves the self-reviews for a specific teacher and user in Native Camp. It checks if the request is an AJAX request and returns the self-reviews data.
12063     *
12064     * @apiBody {String} teacherId The ID of the teacher.
12065     * @apiBody {String} userId The ID of the user.
12066     * 
12067     * @apiSuccess {Object[]} selfReviews The self-reviews data.
12068     * @apiSuccess {String} selfReviews.review The review text.
12069     * @apiSuccess {Number} selfReviews.rating The rating given by the user.
12070     * @apiSuccess {String} selfReviews.date The date of the review.
12071     * @apiSuccess {Number} selfLessonCount The count of lessons taken by the user with the teacher.
12072     * @apiSuccess {Number} daysPast The number of days past since the user's last lesson with the teacher.
12073     * @apiSuccess {String} lessonHistoryTeacherId The ID of the teacher for the lesson history.
12074     *
12075     * @apiSuccessExample {json} Success-Response:
12076     *     {
12077     *         "selfReviews": [
12078     *             {
12079     *                 "review": "Great lesson!",
12080     *                 "rating": 5,
12081     *                 "date": "2023-01-01"
12082     *             },
12083     *             {
12084     *                 "review": "Very helpful.",
12085     *                 "rating": 4,
12086     *                 "date": "2023-01-02"
12087     *             }
12088     *         ],
12089     *         "selfLessonCount": 5,
12090     *         "daysPast": 10,
12091     *         "lessonHistoryTeacherId": "123"
12092     *     }
12093     *
12094     * @apiError {String} error Message indicating the error.
12095     *
12096     * @apiErrorExample {json} Error-Response:
12097     *     {
12098     *         "error": "Invalid request."
12099     *     }
12100     * 
12101     * @apiSampleRequest off
12102     */
12103    public function getSelfReviews() {
12104        $this->layout = "";
12105        $this->autoRender = false;
12106        if (!$this->request->is('ajax')) { return ; }
12107        
12108        $teacherId = $this->request->data['teacherId'];
12109        if (empty($teacherId)) { return ; }
12110
12111        $userId = $this->request->data['userId'];
12112
12113        //get own reviews
12114        $selfReviews = array();
12115        $selfLessonCount = 0;
12116        $daysPast = 0;
12117        if ($userId) {
12118            $selfReviews = $this->getUserReviews($userId, $teacherId);
12119            $selfLessonCount = $this->LessonOnairsLog->countOwnLessons($userId, $teacherId);
12120            $daysPast = $this->LessonOnairsLog->countDaysPast($userId, $teacherId);
12121        }
12122
12123        $this->set('selfReviews', $selfReviews);
12124        $this->set('selfLessonCount', $selfLessonCount);
12125        $this->set('daysPast', $daysPast);
12126        $this->set('lessonHistoryTeacherId',$teacherId);
12127
12128        $this->render('/Elements/self_review');
12129    }
12130
12131    /**
12132     * @api {post} /user/waiting/getGenerationRating getGenerationRating()
12133     * @apiName getGenerationRating
12134     * @apiGroup Waiting
12135     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the rating data.
12136     *
12137     * @apiBody {String} teacherId The ID of the teacher.
12138     * @apiBody {Boolean} [isAvatar] Indicates whether the teacher is an avatar.
12139     * 
12140     * @apiSuccess {Object} rates The generation rating data.
12141     * @apiSuccess {Number} rates.count The total number of ratings.
12142     * @apiSuccess {Number} rates.one_star The number of one-star ratings.
12143     * @apiSuccess {Number} rates.two_star The number of two-star ratings.
12144     * @apiSuccess {Number} rates.three_star The number of three-star ratings.
12145     * @apiSuccess {Number} rates.four_star The number of four-star ratings.
12146     * @apiSuccess {Number} rates.five_star The number of five-star ratings.
12147     * @apiSuccess {Object} rateBreakdown The breakdown of the generation rating data.
12148     * @apiSuccess {Number} rateBreakdown.weekly_average The weekly average rating.
12149     * @apiSuccess {Number} rateBreakdown.monthly_average The monthly average rating.
12150     * @apiSuccess {Number} rateBreakdown.total_average The total average rating.
12151     *
12152     * @apiSuccessExample {json} Success-Response:
12153     *     {
12154     *         "rates": {
12155     *             "count": 100,
12156     *             "one_star": 10,
12157     *             "two_star": 20,
12158     *             "three_star": 30,
12159     *             "four_star": 25,
12160     *             "five_star": 15
12161     *         },
12162     *         "rateBreakdown": {
12163     *             "weekly_average": 4.2,
12164     *             "monthly_average": 4.0,
12165     *             "total_average": 4.1
12166     *         }
12167     *     }
12168     *
12169     * @apiError {String} error Message indicating the error.
12170     *
12171     * @apiErrorExample {json} Error-Response:
12172     *     {
12173     *         "error": "Invalid request."
12174     *     }
12175     * 
12176     * @apiSampleRequest off
12177     */
12178    public function getGenerationRating() {
12179        $this->layout = "";
12180        $this->autoRender = false;
12181        
12182        if (!$this->request->is('ajax')) { return ; }
12183        
12184        $teacherId = Sanitize::escape($this->request->data['teacherId']);
12185        if (empty($teacherId)) { return ; }
12186
12187        $isAvatar = (isset($this->request->data['isAvatar']) && $this->request->data['isAvatar']) ? true : false;
12188        if($isAvatar){
12189            $teacherId = $this->Teacher->getAvatarTeacherId(array('avatar_id' => $teacherId));
12190            $rating = $this->UsersClassEvaluation->getRatings($avatarIds, true);
12191        }
12192
12193        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12194        if ($rating) {
12195            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12196            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12197        }
12198        $this->set('rates', $rates);        
12199        $this->set('rateBreakdown', $rateBreakdown);        
12200
12201        $this->render('teacher_generation_rating');
12202    }
12203
12204    /**
12205     * @api {post} /user/api/getGenerationRating getGenerationRatingAPI()
12206     * @apiName getGenerationRatingAPI
12207     * @apiGroup Waiting
12208     * @apiDescription Retrieves the generation rating data for a specific teacher in Native Camp. It checks the teacher ID and user token, and returns the rating data.
12209     *
12210     * @apiBody {String} teacher_id The ID of the teacher.
12211     * @apiBody {String} users_api_token The API token of the user.
12212     * 
12213     * @apiSuccess {Object} generationData The generation rating data. (0: 20, 1: 30, 2: 50)
12214     *
12215     * @apiSuccessExample {json} Success-Response:
12216     *     {
12217     *         "generationData": {
12218     *             "0": 20,
12219     *             "1": 30,
12220     *             "2": 50
12221     *         }
12222     *     }
12223     *
12224     * @apiError {Object} error The error details.
12225     * @apiError {String} error.id The error ID.
12226     * @apiError {String} error.message The error message.
12227     *
12228     * @apiErrorExample {json} Error-Response (Bad Request):
12229     *     {
12230     *         "error": {
12231     *             "id": "invalid_teacher_id",
12232     *             "message": "teacher_id is invalid"
12233     *         }
12234     *     }
12235      * @apiErrorExample {json} Error-Response (Unauthorized):
12236     *     {
12237     *         "error": {
12238     *             "id": "invalid_token",
12239     *             "message": "users_api_token is invalid"
12240     *         }
12241     *     }
12242     * 
12243     * @apiSampleRequest off
12244     */
12245    public function getGenerationRatingAPI(){
12246        $this->autoRender = false;
12247        $this->layout = false;
12248        $data = json_decode($this->request->input(), true);
12249        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12250        if (empty($teacherId)) { 
12251            $response['error']['id'] = _('invalid_teacher_id');
12252            $response['error']['message'] = __('teacher_id is invalid');
12253            return json_encode($response);
12254        }
12255        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12256        $userData = $this->User->getUserDataByApiToken($userToken);
12257        if(!$userData) {
12258            $response['error']['id'] = _('invalid_token');
12259            $response['error']['message'] = __('users_api_token is invalid');
12260            return json_encode($response);
12261        }
12262        $rating = $this->UsersClassEvaluation->getRatings($teacherId, true);
12263        if ($rating) {
12264            $rates = new UsersClassEvaluationTable($rating['UsersClassEvaluation']);
12265            $rateBreakdown = new UsersClassEvaluationTable($rating['TeacherWeeklyRating']);
12266        }
12267        $ctr = 0;
12268        foreach($rates as $rate){
12269            $generationData[$ctr] = ($rate / $rates->count) * 100; // get percentages for data
12270            $ctr++;
12271        }
12272        //remove count element at the end
12273        array_pop($generationData);
12274        return json_encode($generationData);
12275    }
12276
12277    public function getUserMemo(){
12278        $this->autoRender = false;
12279        $this->layout = false;
12280        $data = json_decode($this->request->input(), true);
12281        $teacherId = isset($data['teacher_id']) ? $data['teacher_id'] : '';
12282        if (empty($teacherId)) { 
12283            $response['error']['id'] = _('invalid_teacher_id');
12284            $response['error']['message'] = __('teacher_id is invalid');
12285            return json_encode($response);
12286        }
12287        $userToken = isset($data['users_api_token']) ? $data['users_api_token'] : '';
12288        $userData = $this->User->getUserDataByApiToken($userToken);
12289        if(!$userData) {
12290            $response['error']['id'] = _('invalid_token');
12291            $response['error']['message'] = __('users_api_token is invalid');
12292            return json_encode($response);
12293        }
12294
12295        $getKeepMemo = $this->UsersMemo->find('first', array(
12296            'fields' => array(
12297                'id',
12298                'memo'
12299            ),
12300            'conditions' => array(
12301                'user_id' => $userData['id'],
12302                'teacher_id' => $teacherId,
12303                'type' => 0
12304            ),
12305            'order' => array('created DESC'),
12306        ));
12307        $memoData['id'] = $getKeepMemo['UsersMemo']['id'];
12308        $memoData['memo'] = $getKeepMemo['UsersMemo']['memo'];
12309        
12310        return json_encode($memoData);
12311    }
12312
12313    /**
12314     * @api {post} /user/waiting/getReservationCancellationBreakdown getReservationCancellationBreakdown()
12315     * @apiName getReservationCancellationBreakdown
12316     * @apiGroup Waiting
12317     * @apiDescription Retrieves the reservation and cancellation breakdown for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation and cancellation data.
12318     *
12319     * @apiBody {String} teacherId The ID of the teacher.
12320     * 
12321     * @apiSuccess {Object} reserveAndCancel The reservation and cancellation breakdown data.
12322     * @apiSuccess {Number} reserveAndCancel.this_month_reserved The number of reservations made this month.
12323     * @apiSuccess {Number} reserveAndCancel.last_month_reserved The number of reservations made last month.
12324     * @apiSuccess {Number} reserveAndCancel.this_month_cancelled The number of reservations cancelled this month.
12325     * @apiSuccess {Number} reserveAndCancel.last_month_cancelled The number of reservations cancelled last month.
12326     * @apiSuccess {Number} reserveAndCancel.this_month_cancellation_rate The cancellation rate this month.
12327     * @apiSuccess {Number} reserveAndCancel.last_month_cancellation_rate The cancellation rate last month.
12328     * 
12329     * @apiSuccessExample {json} Success-Response:
12330     *     {
12331     *         "reserveAndCancel": {
12332     *             "this_month_reserved": 10,
12333     *             "last_month_reserved": 20,
12334     *             "this_month_cancelled": 5,
12335     *             "last_month_cancelled": 10,
12336     *             "this_month_cancellation_rate": 0.5
12337     *         }
12338     *     }
12339     *
12340     * @apiError {String} error Message indicating the error.
12341     *
12342     * @apiErrorExample {json} Error-Response:
12343     *     {
12344     *         "error": "Invalid request."
12345     *     }
12346     * 
12347     * @apiSampleRequest off
12348     */
12349    public function getReservationCancellationBreakdown() {
12350        $this->autoRender = false;
12351        $this->layout = false;
12352        if (!$this->request->is('ajax')) { return ; }
12353        
12354        $teacherId = $this->request->data['teacherId'];
12355        if (empty($teacherId)) { return ; }
12356
12357        //reservation and cancellation breakdown
12358        $reserveAndCancel = $this->getReserveAndCancelled($teacherId);
12359        return json_encode(isset($reserveAndCancel) ? $reserveAndCancel : array());
12360    }
12361
12362    // NJ-22649 transfer functionality from lesson-finish
12363    //not used function
12364    public function getActiveCampaign($params = array()) {
12365        $counseling_flg = (isset($params['counseling_flg']) && $params['counseling_flg']) ? true : false;
12366        $avatar_flg = (isset($params['avatar_flg']) && $params['avatar_flg']) ? true : false;
12367        $chat_hash = (isset($params['chat_hash']) && $params['chat_hash']) ? $params['chat_hash'] : '';
12368        $memberType = (isset($params['memberType']) && $params['memberType']) ? $params['memberType'] : 'student';
12369
12370        $campaignTerm = false;
12371        $modalCampaignType = '';
12372        $campaignPageRecord = '';
12373        $userId = $this->Auth->user('id');
12374        $userData = new UserTable($this->sharedUserData['User']);
12375
12376        $campaignSetting = ClassRegistry::init('CampaignSettingTable');
12377        $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12378        $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12379
12380        //Spring Callan Campaign
12381        $campaignSpringCallanPeriodFrom = Configure::read('campaign_config.callanFirstTime.period.start');
12382        $campaignSpringCallanPeriodTo = Configure::read('campaign_config.callanFirstTime.period.reservation_end');
12383        $campaignSpringCallan = $this->showCampaignModal($campaignSpringCallanPeriodFrom, $campaignSpringCallanPeriodTo);
12384
12385        //Campaign to talk with teachers from all over the world
12386        $campaignGlobalLesson = ClassRegistry::init('CampaignSettingTable')->globalLesson(array('user_id' => $userId, 'type' => 1)); //Check campaign duration date and if not sapuri user
12387        $sixthAnniv3Campaign = ClassRegistry::init('CampaignSettingTable')->sixthAnniv3(array('user_id' => $userId));
12388
12389        //Go to travel campaign
12390        $goToTravelDateArr = Configure::read('campaign_config.gototravel.period');
12391        $goToTravelCampaign = $this->showCampaignModal($goToTravelDateArr['start'], $goToTravelDateArr['end']);
12392
12393        //Alvark Collaboration Campaign
12394        $alvarkCollabCampaign = false;
12395        $alvarkCollabDateArr = Configure::read('campaign_config.alvark_collaboration.period');
12396        $alvarkCollabCheckDate = $this->showCampaignModal($alvarkCollabDateArr['start'], $alvarkCollabDateArr['end']);
12397        if (
12398            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collaboration.valid_memberships')) 
12399            && $userData->currency_code == Configure::read('default.user_currency')
12400            && $alvarkCollabCheckDate
12401            && $this->localizeDir == Configure::read('default.user_language')
12402        ) {
12403            $alvarkCollabCampaign = true;
12404        }
12405
12406        // Campaign Settings Modal
12407        $currStr = $userData->currency_code;
12408        $langId = ClassRegistry::init("CountryCode")->getUserLanguageId($userData->native_language2);
12409        $today = date('Y-m-d H:i:s');
12410        $conditions = array(
12411            'user_plan_type' => $userData->getMembershipTypeIndex(),
12412            'plan_types' => Configure::read('campaign_settings.plan_types'),
12413            'is_sapuri_user' => $userData->isStudySapuri(),
12414            'corporate_user_types' => Configure::read('campaign_settings.corporates'),
12415            'free_user_type' => Configure::read('campaign_settings.free_user_type'),
12416        );
12417
12418        $campaignUserPlanType = $userData->getUserPlanType($conditions);
12419        $this->log("[CampaignSettingsModal][after_lesson] conditions -> " .  json_encode($conditions), "debug");
12420        $campaignSettings = null;
12421        if ((isset($campaignUserPlanType['plan_type']) && $campaignUserPlanType['plan_type']) &&
12422            (isset($campaignUserPlanType['user_type']) && $campaignUserPlanType['user_type'])
12423        ) {
12424            $campaignSettingsModel = ClassRegistry::init('CampaignSettings');
12425            $campaignSettings = $campaignSettingsModel->getActiveAndNotEnded(array(
12426                'fields' => array(
12427                    'CampaignSettings.id',
12428                    'CampaignSettings.modal_html',
12429                    'CampaignSettings.pc_url',
12430                    'CampaignSettings.image_url_pc'
12431                ),
12432                'conditions' => array(
12433                    'CampaignSettings.promo_end >=' => $today,
12434                    'CampaignSettings.status_flag' => 1,
12435                    'CampaignSettings.promo_event_type' => 1, // after lesson
12436                    'CampaignSettings.pc_url IS NOT NULL',
12437
12438                    // os
12439                    array(
12440                        'OR' => array(
12441                            array('CampaignSettings.promo_os LIKE' => '%1%'), // pc
12442                            array('CampaignSettings.promo_os LIKE' => '%0%'), // all
12443                        )
12444                    ),
12445
12446                    // login status
12447                    array(
12448                        'OR' => array(
12449                            array('CampaignSettings.promo_login_status LIKE' => '%1%'), // sign in
12450                            array('CampaignSettings.promo_login_status LIKE' => '%0%'), // all
12451                        )
12452                    ),
12453
12454                    // Plan type
12455                    array(
12456                        'OR' => array(
12457                            array('CampaignSettings.promo_plan_type LIKE' => '%'.$campaignUserPlanType['plan_type'].'%'),
12458                            array('CampaignSettings.promo_plan_type LIKE' => '%0%'), // ALL
12459                        )
12460                    ),
12461
12462                    // User type
12463                    array(
12464                        'OR' => array(
12465                            array('CampaignSettings.promo_user_type LIKE' => '%'.$campaignUserPlanType['user_type'].'%'),
12466                            array('CampaignSettings.promo_user_type LIKE' => '%0%') // ALL
12467                        )
12468                    ),
12469
12470                    // Currency and Language
12471                    array(
12472                        "(SELECT COUNT(*) FROM `campaign_setting_currency` WHERE `CampaignSettings`.`id` = `campaign_setting_currency`.`campaign_setting_id` AND `campaign_setting_currency`.`currency_code` = '".$currStr."') > 0"
12473                    ),
12474                    array(
12475                        "(SELECT COUNT(*) FROM `campaign_setting_language` WHERE `CampaignSettings`.`id` = `campaign_setting_language`.`campaign_setting_id` AND `campaign_setting_language`.`language_id` = '".$langId."') > 0"
12476                    )
12477                ),
12478                'order' => 'CampaignSettings.promo_start ASC'
12479            ));
12480        }
12481
12482        //Marines Collaboration Campaign
12483        $marinesCollabCampaign = false;
12484        $marinesCollabDateArr = Configure::read('campaign_config.going_global_marines_collaboration.period');
12485        $marinesCollabCheckDate = $this->showCampaignModal($marinesCollabDateArr['start'], $marinesCollabDateArr['end']);
12486        if (
12487            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.going_global_marines_collaboration.valid_memberships')) 
12488            && $marinesCollabCheckDate
12489            && $this->localizeDir == Configure::read('default.user_language')
12490        ) {
12491            $marinesCollabCampaign = true;
12492        }
12493
12494        // //Daily News Campaign
12495        // $dailyNewsCampaign = false;
12496        // $dailyNewsDateArr = Configure::read('campaign_config.daily_news.period');
12497        // $dailyNewsCheckDate = $this->showCampaignModal($dailyNewsDateArr['start'], $dailyNewsDateArr['end']);
12498        // if (
12499        //     in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.daily_news.valid_memberships')) 
12500        //     && $dailyNewsCheckDate
12501        // ) {
12502        //     $dailyNewsCampaign = true;
12503        // }
12504
12505        //Favorite Teacher Campaign
12506        $favoriteTeacherCampaign = false;
12507        $favoriteTeacherDateArr = Configure::read('campaign_config.favorite_teacher.period');
12508        $favoriteTeacherCheckDate = $this->showCampaignModal($favoriteTeacherDateArr['start'], $favoriteTeacherDateArr['end']);
12509        if (
12510            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.favorite_teacher.valid_memberships')) 
12511            && $favoriteTeacherCheckDate
12512        ) {
12513            $favoriteTeacherCampaign = true;
12514        }
12515
12516        //Family Plan Campaign
12517        $familyPlanCampaign = false;
12518        $familyPlanDateArr = Configure::read('campaign_config.family_plan.period');
12519        $familyPlanCheckDate = $this->showCampaignModal($familyPlanDateArr['start'], $familyPlanDateArr['end']);
12520        if (
12521            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.family_plan.valid_memberships')) 
12522            && $familyPlanCheckDate
12523        ) {
12524            $familyPlanCampaign = true;
12525        }
12526
12527        //Christmas Campaign
12528        $christmasCampaign = false;
12529        $christmasDateArr = Configure::read('campaign_config.christmas.period');
12530        $christmasCheckDate = $this->showCampaignModal($christmasDateArr['start'], $christmasDateArr['end']);
12531        if (
12532            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.christmas.valid_memberships')) 
12533            && $christmasCheckDate
12534        ) {
12535            $christmasCampaign = true;
12536        }
12537
12538        //New year Part 1 Campaign
12539        $newYearPart1Campaign = false;
12540        $newYearPart1DateArr = Configure::read('campaign_config.new_year_part_1.period');
12541        $newYearPart1CheckDate = $this->showCampaignModal($newYearPart1DateArr['start'], $newYearPart1DateArr['end']);
12542        if (
12543            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_year_part_1.valid_memberships')) 
12544            && ($userData->admin_flg || $newYearPart1CheckDate) 
12545            && $this->localizeDir == Configure::read('default.user_language')
12546        ) {
12547            $newYearPart1Campaign = true;
12548        }
12549
12550        //New grammar Campaign
12551        $newGrammarCampaign = false;
12552        $newGrammarDateArr = Configure::read('campaign_config.new_grammar.period');
12553        $newGrammarCheckDate = $this->showCampaignModal($newGrammarDateArr['start'], $newGrammarDateArr['end']);
12554        if (
12555            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.new_grammar.valid_memberships')) 
12556            && $newGrammarCheckDate
12557        ) {
12558            $newGrammarCampaign = true;
12559        }
12560
12561        //Alvark collab Campaign
12562        $alvarkCollab2Campaign = false;
12563        $alvarkCollab2DateArr = Configure::read('campaign_config.alvark_collab_2.period');
12564        $alvarkCollab2CheckDate = $this->showCampaignModal($alvarkCollab2DateArr['start'], $alvarkCollab2DateArr['end']);
12565        if (
12566            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.alvark_collab_2.valid_memberships')) 
12567            && $alvarkCollab2CheckDate
12568            && $this->localizeDir == Configure::read('default.user_language')
12569        ) {
12570            $alvarkCollab2Campaign = true;
12571        }
12572
12573        //Golden Week NC Campaign
12574        $goldenWeekNCChallengeCampaign = false;
12575        $goldenWeekNCChallengeDateArr = Configure::read('campaign_config.golden_week_nc_challenge.period');
12576        $goldenWeekNCChallengeCheckDate = $this->showCampaignModal($goldenWeekNCChallengeDateArr['start'], $goldenWeekNCChallengeDateArr['end']);
12577        if (
12578            in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.golden_week_nc_challenge.valid_memberships')) 
12579            && $goldenWeekNCChallengeCheckDate
12580        ) {
12581            $goldenWeekNCChallengeCampaign = true;
12582        }
12583
12584        if ($campaignSpringCallan) {
12585            $campaignTerm = $campaignSpringCallan;
12586            $modalCampaignType = 'campaign_callan_half_spring';
12587            $campaignPageRecord = 'callan_half_spring_record';
12588            // check if not a sapuri student
12589            $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12590            if (in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.callanFirstTime.membership'))) {        
12591                /* count callan lesson taken within the campaign period */
12592                $countCallanLesson = ClassRegistry::init('CampaignSettingTable')->callanMarathonCampaign(array(
12593                    'user_id' => $this->Auth->user("id"),
12594                    'date_period' => array(
12595                            Configure::read('campaign_config.callanFirstTime.period.start'),
12596                            Configure::read('campaign_config.callanFirstTime.period.reservation_end')
12597                        ),
12598                    'tb_category_id' => Configure::read('campaign_config.callanFirstTime.textbook_category')
12599                ));
12600                $response['countCallanLesson'] = $countCallanLesson;
12601            }
12602
12603        } else if ($campaignGlobalLesson) {
12604            //If not counseling: display modal stamp
12605            if (!$counseling_flg) {
12606                $campaignTerm = $campaignGlobalLesson;
12607                $modalCampaignType = 'campaign_global_lesson';
12608                $campaignPageRecord = 'global_lesson_record';
12609            }
12610        } else if ($sixthAnniv3Campaign) {
12611            $campaignTerm = $sixthAnniv3Campaign;
12612            $modalCampaignType = 'campaign_sixth_anniv_3';
12613            $campaignPageRecord = 'sixth_anniv_record';
12614
12615        //Go to travel campaign
12616        } else if ($goToTravelCampaign) {
12617            if (!$counseling_flg) {
12618                $userData = new UserTable( $this->sharedUserData[ 'User' ] );
12619                $stampAchieved = array();
12620                if (!in_array($userData->getMembershipTypeIndex(), Configure::read('campaign_config.gototravel.membership_invalid'))) {
12621                    // get student achieved lesson stamps
12622                    $stampAchieved = ClassRegistry::init('CampaignSettingTable')->camapaignGoToTravelTbStamp(array(
12623                        'user_id' => $this->Auth->user( 'id' ),
12624                        'start_time' => Configure::read('campaign_config.gototravel.period.start'),
12625                        'end_time' => Configure::read('campaign_config.gototravel.period.end'),
12626                        'tb_connect_ids' => array_values(array_flip(Configure::read('campaign_config.gototravel.textbook_connect'))),
12627                        'lesson_min_time' => Configure::read('campaign_config.gototravel.lesson_time')
12628                    ));
12629                    $stampAchieved = is_array($stampAchieved) ? array_values($stampAchieved) : $stampAchieved;
12630                    $response['stampAchieved'] = $stampAchieved;
12631                    $modalCampaignType = 'campaign_gototravel_is_back';
12632                    $campaignPageRecord = 'gototravel_is_back_record';
12633                    $campaignTerm = $goToTravelCampaign;
12634                }
12635            }
12636        } else if ($alvarkCollabCampaign) {
12637            if (!$counseling_flg) {
12638                $cst = ClassRegistry::init('CampaignSettingTable');
12639                $campaignStamps = $cst->alvarkCollaboration(
12640                    array(
12641                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12642                        'type' => 1,
12643                    )
12644                );
12645                $response['campaignStamps'] = $campaignStamps;
12646                $modalCampaignType = 'campaign_going_global_alvark_live';
12647                $campaignTerm = $alvarkCollabCampaign;
12648            }
12649        } 
12650
12651        if ($campaignSettings) {
12652            $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12653            $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12654            $showCampaignSettingsCampModal = array();
12655            foreach ($campaignSettings as $key => $value) {
12656                $id = $value['CampaignSettings']['id'];
12657                if (!in_array($id, $dontShowCampaignModals)) {
12658                    $showCampaignSettingsCampModal[] = $id;
12659                }
12660            }
12661            $response['campaignSettings'] = $campaignSettings;
12662            $response['showCampaignSettingsCampModal'] = $showCampaignSettingsCampModal;
12663            $response['campaignSettingsAfterLeson'] = true;
12664        } else if ($marinesCollabCampaign) {
12665            if (!$counseling_flg) {
12666                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12667                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12668                $marinesCollabCampPeriod = Configure::read('campaign_config.going_global_marines_collaboration.period');
12669                $marinesCollabCampaignSettingId = Configure::read('campaign_config.going_global_marines_collaboration.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12670    
12671                $response['marinesCollabCampaignSettingId'] = $marinesCollabCampaignSettingId;
12672                $response['marinesCollabCampaign'] = $marinesCollabCampaign;
12673                $response['showMarinesCollabCampModal'] = (!in_array($marinesCollabCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12674
12675                $cst = ClassRegistry::init('CampaignSettingTable');
12676                $campaignStamps = $cst->marinesCollaboration(
12677                    array(
12678                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12679                        'type' => 1,
12680                        'display_type' => 1,
12681                    )
12682                );
12683                $response['campaignStamps'] = $campaignStamps;
12684                $modalCampaignType = 'campaign_going_global_marines_live';
12685                $campaignTerm = $marinesCollabCampaign;
12686            }
12687        }
12688        // if ($dailyNewsCampaign) {
12689        //     if (!$counseling_flg) {
12690        //         $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12691        //         $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12692        //         $dailyNewsCampaignSettingId = Configure::read('campaign_config.daily_news.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12693
12694        //         $response['dailyNewsCampaignSettingId'] = $dailyNewsCampaignSettingId;
12695        //         $response['dailyNewsCampaign'] = $dailyNewsCampaign;
12696        //         $response['showDailyNewsCampModal'] = (!in_array($dailyNewsCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12697
12698        //         $cst = ClassRegistry::init('CampaignSettingTable');
12699        //         $campaignStamps = $cst->dailyNews(
12700        //             array(
12701        //                 'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12702        //                 'type' => 1
12703        //             )
12704        //         );
12705        //         $response['campaignStamps'] = $campaignStamps;
12706        //         $modalCampaignType = 'campaign_dailynews_live';
12707        //         $campaignTerm = $dailyNewsCampaign;
12708        //     }
12709        // }
12710
12711        if ($favoriteTeacherCampaign) {
12712            if (!$counseling_flg) {
12713                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12714                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12715                $favoriteTeacherCampaignSettingId = Configure::read('campaign_config.favorite_teacher.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12716
12717                $response['favoriteTeacherCampaignSettingId'] = $favoriteTeacherCampaignSettingId;
12718                $response['favoriteTeacherCampaign'] = $favoriteTeacherCampaign;
12719                $response['showFavoriteTeacherCampModal'] = (!in_array($favoriteTeacherCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12720
12721                $cst = ClassRegistry::init('CampaignSettingTable');
12722                $campaignStamps = $cst->favoriteTeacher(
12723                    array(
12724                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12725                        'type' => 1,
12726                        'requested_events' => array(1)
12727                    )
12728                );
12729                $response['campaignStamps'] = $campaignStamps['event1'];
12730                $modalCampaignType = 'campaign_favorite_teachers_live';
12731                $campaignTerm = $favoriteTeacherCampaign;
12732            }
12733        }
12734
12735        if ($familyPlanCampaign) {
12736            if (!$counseling_flg) {
12737                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12738                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12739                $familyPlanCampaignSettingId = Configure::read('campaign_config.family_plan.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12740
12741                $response['familyPlanCampaignSettingId'] = $familyPlanCampaignSettingId;
12742                $response['familyPlanCampaign'] = $familyPlanCampaign;
12743                $response['showFamilyPlanCampModal'] = (!in_array($familyPlanCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12744
12745                $cst = ClassRegistry::init('CampaignSettingTable');
12746                $lessonLogsFPC = $cst->familyPlan(
12747                    array(
12748                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12749                        'type' => 1
12750                    )
12751                );
12752                $response['lessonLogsFPC'] = $lessonLogsFPC;
12753                $modalCampaignType = 'campaign_plan_family_live';
12754                $campaignTerm = $familyPlanCampaign;
12755            }
12756        }
12757
12758        if ($christmasCampaign) {
12759            if (!$counseling_flg) {
12760                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12761                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12762                $christmasCampaignSettingId = Configure::read('campaign_config.christmas.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12763
12764                $response['christmasCampaignSettingId'] = $christmasCampaignSettingId;
12765                $response['christmasCampaign'] = $christmasCampaign;
12766                $response['showChristmasCampModal'] = (!in_array($christmasCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12767
12768                $cst = ClassRegistry::init('CampaignSettingTable');
12769                $lessonStamps = $cst->christmas(
12770                    array(
12771                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12772                        'type' => 1,
12773                    )
12774                );
12775                $response['lessonStamps'] = $lessonStamps;
12776                $modalCampaignType = 'campaign_christmas_live';
12777                $campaignTerm = $christmasCampaign;
12778            }
12779        }
12780
12781        if ($newYearPart1Campaign) {
12782            $campaignID = Configure::read('campaign_config.new_year_part_1.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_login');
12783            $lotteryData = array();
12784            $cst = ClassRegistry::init('CampaignSettingTable');
12785            $newYearLessonData = $cst->checkLastLesson(
12786                array(
12787                    'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12788                    'chat_hash' => $chat_hash,
12789                    'campaign_id' => $campaignID[0]
12790                )
12791            );
12792            $response['newYearPart1Campaign'] = $newYearPart1Campaign;
12793            $response['showNewYearPart1CampModal'] = ($newYearLessonData) ? true : false;
12794            $modalCampaignType = ($newYearLessonData) ? 'campaign_new_year_afterlesson' : '';
12795            $campaignTerm = $newYearPart1Campaign;
12796        }
12797
12798        if ($newGrammarCampaign) {
12799            if (!$counseling_flg) {
12800                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12801                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12802                $newGrammarCampaignSettingId = Configure::read('campaign_config.new_grammar.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12803    
12804                $response['newGrammarCampaignSettingId'] = $newGrammarCampaignSettingId;
12805                $response['newGrammarCampaign'] = $newGrammarCampaign;
12806                $response['showNewGrammarCampAfterLessonModal'] = (!in_array($newGrammarCampaignSettingId, $dontShowCampaignModals)) ? true : false;
12807
12808                $cst = ClassRegistry::init('CampaignSettingTable');
12809                $campaignStamps = $cst->newGrammar(
12810                    array(
12811                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12812                        'type' => 1
12813                    )
12814                );
12815                $response['campaignStamps'] = $campaignStamps;
12816                $modalCampaignType = 'campaign_newgrammar_live';
12817                $campaignTerm = $newGrammarCampaign;
12818            }
12819        }
12820
12821        if ($alvarkCollab2Campaign) {
12822            if (!$counseling_flg) {
12823                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12824                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12825                $alvarkCollab2CampaignSettingId = Configure::read('campaign_config.alvark_collab_2.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12826    
12827                $response['alvarkCollab2CampaignSettingId'] = $alvarkCollab2CampaignSettingId;        
12828                $response['alvarkCollab2Campaign'] = $alvarkCollab2Campaign;
12829                $response['showAlvarkCollab2CampAfterLessonModal'] = (!in_array($alvarkCollab2CampaignSettingId, $dontShowCampaignModals)) ? true : false;    
12830
12831                $cst = ClassRegistry::init('CampaignSettingTable');
12832                $avk2coupon = $cst->alvarkCollab2(
12833                    array(
12834                        'user_id' => ($this->Auth->loggedIn()) ? $this->Auth->user('id') : null,
12835                        'type' => 1
12836                    )
12837                );
12838                $response['avk2coupon'] = $avk2coupon;
12839                $modalCampaignType = 'mypage_going_global_alvark_live';
12840                $campaignTerm = $alvarkCollab2Campaign;
12841            }
12842        }
12843
12844        if ($goldenWeekNCChallengeCampaign) {
12845            if (!$counseling_flg) {
12846                $userCampaignModalSetting = ClassRegistry::init('UserCampaignModalSettings');
12847                $dontShowCampaignModals = $userCampaignModalSetting->getDontShowCampaignModals(array('user_id' => $userData->id));
12848                $campModalSettingIDs = Configure::read('campaign_config.golden_week_nc_challenge.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12849                $goldenWeekNCChallengeCampaignSettingId = ($memberType == 'student') ? $campModalSettingIDs['after_lesson'] : $campModalSettingIDs['after_live_lesson_viewer'];
12850
12851                $cst = ClassRegistry::init('CampaignSettingTable');
12852                $check = $cst->checkGoldenWeekChallengeModals(array(
12853                    'user_id' => $userData->id,
12854                    'chat_hash' => $chat_hash,
12855                    'camp_setting_id' => $goldenWeekNCChallengeCampaignSettingId
12856                ));
12857
12858                //Get stamp
12859                $goldenWeekNCChallengeStamp = $cst->goldenWeekChallenge(
12860                    array(
12861                        'user_id' => $userData->id,
12862                        'type' => 1,
12863                        'challenge_stamp' => ($memberType == 'student') ? 3 : 2
12864                    )
12865                );
12866
12867                $displayModalAfterLesson = (!in_array($goldenWeekNCChallengeCampaignSettingId, $dontShowCampaignModals) && $check) ? true : false;
12868                
12869                $response['goldenWeekNCChallengeStamp'] = $goldenWeekNCChallengeStamp;
12870                $response['goldenWeekNCChallengeCampaignSettingId'] = $goldenWeekNCChallengeCampaignSettingId;
12871                $response['goldenWeekNCChallengeCampaignAfterLesson'] = $goldenWeekNCChallengeCampaign;
12872                $response['showGoldenWeekNCChallengeCampAfterLessonModal'] = $displayModalAfterLesson;
12873
12874                $modalCampaignType = ($memberType == 'student') ? 'campaign_golden_week_lesson' : 'campaign_golden_week_live';
12875                $modalCampaignType = ($displayModalAfterLesson) ? $modalCampaignType : '';
12876                $campaignTerm = $goldenWeekNCChallengeCampaign;
12877            }
12878        }
12879
12880
12881        //NJ-21995 Super native camp festival campaign
12882        $superNativeCamp = array(
12883            'campaign' => 'super_native_camp',
12884            'user_membership' => $userData->getMembershipTypeIndex()
12885        );
12886        if(!$counseling_flg && $campaignSetting->campaignChecker($superNativeCamp)){
12887            $campModalSettingIDs = Configure::read('campaign_config.super_native_camp.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12888            $superNativeCampFestivalCampSettingID = $campModalSettingIDs['after_lesson'];
12889            $campaignTotalMinsOfLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 1));
12890            $checkCampaignLesson = $campaignSetting->superNativeCampFestival(array('user_id' => $userData->id, 'type' => 3, 'chat_hash' => $chat_hash));
12891            $displayModalAfterLesson = (!in_array($superNativeCampFestivalCampSettingID, $dontShowCampaignModals) && $checkCampaignLesson) ? true : false;;
12892            $response['campaignTotalMinsOfLesson'] = $campaignTotalMinsOfLesson;
12893            $response['superNativeCampFestivalCampSettingID'] = $superNativeCampFestivalCampSettingID;
12894            $response['showSuperNativeCampFestivalCampAfterLessonModal'] = $displayModalAfterLesson;
12895
12896            $modalCampaignType = 'campaign_nc_festival_live';
12897            $campaignTerm = true;
12898        }
12899
12900        //NJ-25217 Online English Conversation No.1 Festival
12901        $camp_OECF = array(
12902            'campaign' => 'OECF',
12903            'user_membership' => $userData->getMembershipTypeIndex(),
12904            'allow_language' => array(Configure::read('default.user_language'), 'en'),
12905            'user_language' => ($this->localizeDir == Configure::read('default.user_language') && in_array($userData->native_language2, array(Configure::read('default.user_language'), 'en'))) ? Configure::read('default.user_language') : $this->localizeDir,
12906            'user_currency' => $userData->currency_code,
12907            'allow_currency' => ($userData->native_language2 == 'en') ? array(Configure::read('default.user_currency')) : null
12908        );
12909        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_OECF)){
12910            $campModalSettingIDs = Configure::read('campaign_config.OECF.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings');
12911            $camp_OECF_setting_ID = $campModalSettingIDs['after_lesson'][0];
12912            $dataStamp = $campaignSetting->onlineEnglishConversationFestival(array('user_id' => $userData->id, 'type' => 1, 'device' => 1));
12913            $displayModalAfterLesson = (!in_array($camp_OECF_setting_ID, $dontShowCampaignModals)) ? true : false;
12914            $response['dataStamp'] = $dataStamp;
12915            $response['OECFCampSettingID'] = $camp_OECF_setting_ID;
12916            $response['showOECFCampAfterLessonModal'] = $displayModalAfterLesson;
12917
12918            $modalCampaignType = 'campaign_nc_no1_festival_live';
12919            $campaignTerm = true;
12920        }
12921
12922        // - NJ-31307 Callan Unlimited Campaign
12923        $camp_callan_unlimited = array(
12924            'campaign' => 'callan_unlimited',
12925            'user_membership' => $userData->getMembershipTypeIndex()
12926        );
12927        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_callan_unlimited)){
12928            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12929            $displayModalAfterLesson = (!in_array($camp_callan_unlimited_ID, $dontShowCampaignModals)) ? true : false;
12930            if($displayModalAfterLesson){
12931                $modalCampaignType = 'campaign_callan_unlimited_afterlesson';
12932                $campaignTerm = true;
12933            }
12934        }
12935
12936        // - NJ-32989 : New Year Lottery Campaign
12937        $camp_new_year_lottery = array(
12938            'campaign' => 'new_year_lottery',
12939            'user_membership' => $userData->getMembershipTypeIndex(),
12940            'user_language' => $userData->native_language2,
12941            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
12942            'user_currency' => $userData->currency_code,
12943            'other_validation' => true,
12944        );
12945        if($campaignSetting->campaignChecker($camp_new_year_lottery)){
12946            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12947            $displayModalAfterLesson = (!in_array($camp_new_year_lottery_ID[0], $dontShowCampaignModals)) ? true : false;
12948            if($displayModalAfterLesson){
12949                $modalCampaignType = 'campaign_new_year_afterlesson';
12950                $campaignTerm = true;
12951            }
12952        }
12953
12954        // - NJ-32989 Around the world campaign
12955        $camp_around_the_world = array(
12956            'campaign' => 'around_the_world',
12957            'user_membership' => $userData->getMembershipTypeIndex(),
12958            'user_currency' => $userData->currency_code,
12959            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
12960            'user_language' => $userData->native_language2,
12961            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
12962        );
12963        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_around_the_world)){
12964            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
12965            $displayModalAfterLesson = (!in_array($camp_around_the_world_ID, $dontShowCampaignModals)) ? true : false;
12966            if($displayModalAfterLesson){
12967                $modalCampaignType = 'campaign_around_the_world_afterlesson';
12968                $campaignTerm = true;
12969            }
12970        }
12971
12972        // - NJ-36818 : What are you doing now? Native Camp! Campaign
12973        $camp_spare_time = array(
12974            'campaign' => 'spare_time_march',
12975            'user_membership' => $userData->getMembershipTypeIndex(),
12976            'user_language' => $userData->native_language2,
12977            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
12978        );
12979        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_spare_time)){
12980            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12981            $displayModalAfterLesson = (!in_array($camp_spare_time_ID, $dontShowCampaignModals)) ? true : false;
12982            if($displayModalAfterLesson){
12983                $modalCampaignType = 'campaign_spare_time_afterlesson';
12984                $campaignTerm = true;
12985            }
12986        }
12987
12988        // - NJ-39740 : 1.5 Million - Thank You Campaign
12989        $camp_opfm = array(
12990            'campaign' => 'OPFM_campaign',
12991            'user_membership' => $userData->getMembershipTypeIndex(),
12992            'user_language' => $userData->native_language2,
12993            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
12994        );
12995        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_opfm)){
12996            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
12997            $displayModalAfterLesson = (!in_array($camp_opfm_ID, $dontShowCampaignModals)) ? true : false;
12998            if($displayModalAfterLesson){
12999                $modalCampaignType = 'campaign_150_ten_thousand_afterlesson';
13000                $campaignTerm = true;
13001            }
13002        }
13003
13004        // - NJ-42488 : kakaku_01 campaign
13005        $camp_kakaku01 = array(
13006            'campaign' => 'kakaku_01',
13007            'user_membership' => $userData->getMembershipTypeIndex(),
13008        );
13009        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_kakaku01)){
13010            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13011            if($userData->native_language2 == Configure::read('default.user_language')){
13012                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[0], $dontShowCampaignModals)) ? true : false;
13013                if($displayModalAfterLesson){
13014                    $modalCampaignType = 'campaign_kakaku_01_live';
13015                    $campaignTerm = true;
13016                }
13017            } else {
13018                $displayModalAfterLesson = (!in_array($camp_kakaku_01_IDs[1], $dontShowCampaignModals)) ? true : false;
13019                if($displayModalAfterLesson){
13020                    $modalCampaignType = 'campaign_dailynews_live';
13021                    $campaignTerm = true;
13022                }
13023            }
13024        }
13025
13026        // - NJ-45886 [Campaign] AI Speaking Campaign
13027        $camp_ai_speaking_sept = array(
13028            'campaign' => 'ai_speaking_sept',
13029            'user_membership' => $userData->getMembershipTypeIndex(),
13030            'user_language' => $userData->native_language2,
13031            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages'),
13032        );
13033        if(!$counseling_flg && $campaignSetting->campaignChecker($camp_ai_speaking_sept)){
13034            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13035            $displayModalAfterLesson = (!in_array($camp_ai_speaking_sept_IDs[0], $dontShowCampaignModals)) ? true : false;
13036            if($displayModalAfterLesson){
13037                $modalCampaignType = 'campaign_speaking_afterlesson';
13038                $campaignTerm = true;
13039            }
13040        }
13041
13042        //NJ-50048 Lesson coin gift campaign
13043        $lessonCoinGiftCamp = array(
13044            'campaign' => 'taking_lesson_and_continue_plan',
13045            'user_membership' => $userData->getMembershipTypeIndex(),
13046            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13047            'user_language' => $userData->native_language2,
13048        );
13049        if(!$counseling_flg && $campaignSetting->campaignChecker($lessonCoinGiftCamp)){
13050            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13051            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13052            $displayModalAfterLesson = (!in_array($lessonCoinGiftCampSettingID, $dontShowCampaignModals)) ? true : false;
13053            if($displayModalAfterLesson){
13054                $modalCampaignType = 'campaign_lesson_coin_gift_live';
13055                $campaignTerm = true;
13056            }
13057        }
13058
13059        //NJ-55569 2025 New Year Campaign
13060        $newYearCamp = array(
13061            'campaign' => 'newyear_2025',
13062            'user_membership' => $userData->getMembershipTypeIndex(),
13063            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13064            'user_language' => $userData->native_language2,
13065            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13066            'user_currency' => $userData->currency_code,
13067        );
13068        if(!$counseling_flg && $campaignSetting->campaignChecker($newYearCamp)){
13069            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13070            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13071            if($userData->native_language2 == Configure::read('default.user_language')){
13072                $displayModalAfterLesson = (!in_array($newYearCampSettingID[0], $dontShowCampaignModals)) ? true : false;
13073                if($displayModalAfterLesson){
13074                    $modalCampaignType = 'campaign_new_year_live';
13075                    $campaignTerm = true;
13076                }
13077            } else {
13078                $displayModalAfterLesson = (!in_array($newYearCampSettingID[1], $dontShowCampaignModals)) ? true : false;
13079                if($displayModalAfterLesson){
13080                    $modalCampaignType = 'campaign_dailynews_live';
13081                    $campaignTerm = true;
13082                }
13083            }
13084        }
13085
13086        //NJ-59889 3 Million Campaign
13087        $threeMillionCamp = array(
13088            'campaign' => '3_million',
13089            'user_membership' => $userData->getMembershipTypeIndex(),
13090            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13091            'user_language' => $userData->native_language2,
13092            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13093            'user_currency' => $userData->currency_code,
13094        );
13095        if(!$counseling_flg && $campaignSetting->campaignChecker($threeMillionCamp)){
13096            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13097            $displayModalAfterLesson = (!in_array($threeMillionCampSettingId, $dontShowCampaignModals)) ? true : false;
13098            if($displayModalAfterLesson){
13099                $modalCampaignType = 'campaign_3_million_afterlesson';
13100                $campaignTerm = true;
13101            }
13102        }
13103
13104        // - NJ-65066 【Campaign】Daily Topics
13105        $dailytopicsCamp = array(
13106            'campaign' => 'daily_topics',
13107            'user_membership' => $userData->getMembershipTypeIndex(),
13108            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13109            'user_language' => $userData->native_language2,
13110            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13111            'user_currency' => $userData->currency_code,
13112        );
13113        if(!$counseling_flg && $campaignSetting->campaignChecker($dailytopicsCamp)){
13114            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13115            $displayModalAfterLesson = (!in_array($dailytopicsCampSettingId, $dontShowCampaignModals)) ? true : false;
13116            if($displayModalAfterLesson){
13117                $modalCampaignType = 'campaign_dailytopics_afterlesson';
13118                $campaignTerm = true;
13119            }
13120        }
13121
13122        $response['campaign_name'] = $modalCampaignType;
13123        $response['campaignPageRecord'] = $campaignPageRecord;
13124        $response['campaignTerm'] = $campaignTerm;
13125
13126        return $response;
13127    }
13128
13129
13130    //Retrieves the active campaign stamp data for the authenticated user in Native Camp. It checks various campaigns and sets the campaign data for the view.
13131    public function getActiveCampaignStampData($params = []) {
13132
13133        $usrObj = new UserTable($this->sharedUserData['User']);
13134        $cst_ = ClassRegistry::init('CampaignSettingTable');
13135
13136        // - NJ-31307 Callan unlimited campaign
13137        $camp_callan_unlimited = array(
13138            'campaign' => 'callan_unlimited',
13139            'user_membership' => $usrObj->getMembershipTypeIndex()
13140        );
13141        if($cst_->campaignChecker($camp_callan_unlimited)){
13142            $campaignStamp = $cst_->callanUnlimitedCampaign(array(
13143                'trigger' => 1,
13144                'user_id' => $usrObj->id
13145            ));
13146            $camp_callan_unlimited_ID = Configure::read('campaign_config.callan_unlimited.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13147            $this->set('campaignStamp', $campaignStamp);
13148            $this->set('callanUnlimitedSettingID', $camp_callan_unlimited_ID);
13149            $this->set('showCallanUnlimitedAfterLessonModal', true);
13150        }
13151
13152        // - NJ-32989 : New Year Lottery Campaign
13153        $camp_new_year_lottery = array(
13154            'campaign' => 'new_year_lottery',
13155            'user_membership' => $usrObj->getMembershipTypeIndex(),
13156            'user_language' => $usrObj->native_language2,
13157            'allow_language' => Configure::read('campaign_config.new_year_lottery.allow_languages'),
13158            'user_currency' => $usrObj->currency_code,
13159            'other_validation' => true,
13160        );
13161        if($cst_->campaignChecker($camp_new_year_lottery)){
13162            $campaignLotteryTicket = $cst_->newYearLotteryCamp(array(
13163                'trigger' => 1,
13164                'user_id' => $usrObj->id
13165            ));
13166            $camp_new_year_lottery_ID = Configure::read('campaign_config.new_year_lottery.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13167            $this->set('campaignLotteryTicket', $campaignLotteryTicket);
13168            $this->set('newYearLotterySettingID', $camp_new_year_lottery_ID[0]);
13169            $this->set('showNewYearLotteryAfterLessonModal', true);
13170        }
13171
13172        // - NJ-32989 Around the world campaign
13173        $camp_around_the_world = array(
13174            'campaign' => 'around_the_world',
13175            'user_membership' => $usrObj->getMembershipTypeIndex(),
13176            'user_currency' => $usrObj->currency_code,
13177            'allow_currency' => Configure::read('campaign_config.around_the_world.allow_currencies'),
13178            'user_language' => $usrObj->native_language2,
13179            'allow_language' => Configure::read('campaign_config.around_the_world.allow_languages'),
13180
13181        );
13182        if($cst_->campaignChecker($camp_around_the_world)){
13183            $stampData = ClassRegistry::init('CampaignSettingTable')->aroundTheWorldCamp(['user_id' => $usrObj->id, 'trigger' => 1]);
13184            $camp_around_the_world_ID = Configure::read('campaign_config.around_the_world.modal_settings.after_lesson');
13185            $this->set('aroundTheWorldSettingID', $camp_around_the_world_ID);
13186            $this->set('showAroundTheWorldAfterLessonModal', true);
13187            $this->set('total_stamp_count', $stampData['total_count'] ?? 0 );
13188            $this->set('stamp_html', $stampData['stamp_html'] ?? '' );
13189        }
13190
13191        // - NJ-36818 : What are you doing now? Native Camp! Campaign
13192        $camp_spare_time = array(
13193            'campaign' => 'spare_time_march',
13194            'user_membership' => $usrObj->getMembershipTypeIndex(),
13195            'user_language' => $usrObj->native_language2,
13196            'allow_language' => Configure::read('campaign_config.spare_time_march.allow_languages'),
13197        );
13198        if($cst_->campaignChecker($camp_spare_time)){
13199            $campaignStamp = $cst_->spareTimeCampaign(array(
13200                'trigger' => 1,
13201                'user_id' => $usrObj->id
13202            ));
13203            $camp_spare_time_ID = Configure::read('campaign_config.spare_time_march.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13204            $this->set('spareTimeCampaignStamp', $campaignStamp);
13205            $this->set('spareTimeSettingID', $camp_spare_time_ID);
13206            $this->set('showSpareTimeAfterLessonModal', true);
13207        }
13208
13209        // 1.5 Million - Thank You Campaign
13210        $camp_opfm = array(
13211            'campaign' => 'OPFM_campaign',
13212            'user_membership' => $usrObj->getMembershipTypeIndex(),
13213            'user_language' => $usrObj->native_language2,
13214            'allow_language' => Configure::read('campaign_config.OPFM_campaign.allow_languages'),
13215        );
13216        if($cst_->campaignChecker($camp_opfm)){
13217            $campaignStamp = $cst_->opfmCampaign(array(
13218                'trigger' => 1,
13219                'user_id' => $usrObj->id
13220            ));
13221            $camp_opfm_ID = Configure::read('campaign_config.OPFM_campaign.ENV.'.Configure::read('ENVIRONMENT').'.modal_settings.after_lesson');
13222            $this->set('opfmCampaignStamp', $campaignStamp);
13223            $this->set('opfmSettingID', $camp_opfm_ID);
13224            $this->set('showOpfmAfterLessonModal', true);
13225        }
13226
13227        // - NJ-42488 : kakaku_01 campaign
13228        $camp_kakaku01 = array(
13229            'campaign' => 'kakaku_01',
13230            'user_membership' => $usrObj->getMembershipTypeIndex()
13231        );
13232        if($cst_->campaignChecker($camp_kakaku01)){
13233            $kakakuCampaignStamp = ClassRegistry::init('CampaignSettingTable')->kakaku01_camp(array(
13234                'trigger' => 1,
13235                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13236            ));
13237            $camp_kakaku_01_IDs = Configure::read('campaign_config.kakaku_01.modal_settings.after_lesson');
13238            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13239                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13240                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[0]);
13241                $this->set('showKakaku01AfterLessonModal', true);
13242            } else {
13243                $this->set('kakakuCampaignStamp', $kakakuCampaignStamp);
13244                $this->set('kakaku01SettingID', $camp_kakaku_01_IDs[1]);
13245                $this->set('showKakaku01DailyNewsAfterLessonModal', true);
13246            }
13247        }
13248
13249        // - NJ-42488 : kakaku_01 campaign
13250        $camp_ai_speaking_sept = array(
13251            'campaign' => 'ai_speaking_sept',
13252            'user_membership' => $usrObj->getMembershipTypeIndex(),
13253            'user_language' => $usrObj->native_language2,
13254            'allow_language' => Configure::read('campaign_config.ai_speaking_sept.allow_languages')
13255        );
13256        if($cst_->campaignChecker($camp_ai_speaking_sept)){
13257            $aiSpeakingSeptCampaignStamp = ClassRegistry::init('CampaignSettingTable')->ai_speaking_camp(array(
13258                'trigger' => 1,
13259                'user_id' => ($this->Auth->loggedIn()) ? $usrObj->id : null,
13260            ));
13261            $camp_ai_speaking_sept_IDs = Configure::read('campaign_config.ai_speaking_sept.modal_settings.after_lesson');
13262            $this->set('aiSpeakingSeptCampaignStamp', $aiSpeakingSeptCampaignStamp);
13263            $this->set('aiSpeakingSeptSettingID', $camp_ai_speaking_sept_IDs[0]);
13264            $this->set('showAISpeakingSeptAfterLessonModal', true);
13265        }
13266
13267        //NJ-50048 Lesson coin gift campaign
13268        $lessonCoinGiftCamp = array(
13269            'campaign' => 'taking_lesson_and_continue_plan',
13270            'user_membership' => $usrObj->getMembershipTypeIndex(),
13271            'allow_language' => Configure::read('campaign_config.taking_lesson_and_continue_plan.allowed_languages'),
13272            'user_language' => $usrObj->native_language2,
13273        );
13274        if($cst_->campaignChecker($lessonCoinGiftCamp)){
13275            $campModalSettingIDs = Configure::read('campaign_config.taking_lesson_and_continue_plan.modal_settings');
13276            $lessonCoinGiftCampSettingID = $campModalSettingIDs['after_lesson'];
13277            $dataStamp = $cst_->takingLessonAndContinuePlan(array('user_id' => $usrObj->id, 'type' => 1, 'device' => 1));
13278            $this->set('dataStamp', $dataStamp);
13279            $this->set('lessonCoinGiftCampSettingID', $lessonCoinGiftCampSettingID);
13280            $this->set('showLessonCoinGiftCampAfterLessonModal', true);
13281        }
13282
13283        //NJ-55569 2025 New Year Campaign
13284        $newYearCamp = array(
13285            'campaign' => 'newyear_2025',
13286            'user_membership' => $usrObj->getMembershipTypeIndex(),
13287            'allow_language' => Configure::read('campaign_config.newyear_2025.allowed_languages'),
13288            'user_language' => $usrObj->native_language2,
13289            'allow_currency' => Configure::read('campaign_config.newyear_2025.allowed_currencies'),
13290            'user_currency' => $usrObj->currency_code,
13291        );
13292        if($cst_->campaignChecker($newYearCamp)){
13293            $campModalSettingIDs = Configure::read('campaign_config.newyear_2025.modal_settings');
13294            $newYearCampSettingID = $campModalSettingIDs['after_lesson'];
13295            $newyear2025_stamp = $cst_->newyear2025_camp(array('user_id' => $usrObj->id, 'trigger' => 1));
13296            $this->set('newyear2025_stamp', $newyear2025_stamp);
13297
13298            if( $usrObj->native_language2 == Configure::read('default.user_language')){
13299                $this->set('showNewYearCampAfterLessonModal', true);
13300                $this->set('newYearCampSettingID', $newYearCampSettingID[0]);
13301            } else {
13302                $this->set('showNewYearDailyNewsCampAfterLessonModal', true);
13303                $this->set('newYearCampSettingID', $newYearCampSettingID[1]);
13304            }
13305        }
13306
13307        //NJ-59889 3 Million Campaign
13308        $threeMillionCamp = array(
13309            'campaign' => '3_million',
13310            'user_membership' => $usrObj->getMembershipTypeIndex(),
13311            'allow_language' => Configure::read('campaign_config.3_million.allowed_languages'),
13312            'user_language' => $usrObj->native_language2,
13313            'allow_currency' => Configure::read('campaign_config.3_million.allowed_currencies'),
13314            'user_currency' => $usrObj->currency_code,
13315        );
13316        if($cst_->campaignChecker($threeMillionCamp)){
13317            $threeMillionCampSettingId = Configure::read('campaign_config.3_million.modal_settings.after_lesson');
13318            $campaignStamp = $cst_->threeMillionCamp([
13319                'trigger' => 1,
13320                'user_id' => $usrObj->id,
13321                'lang' => $this->localizeDir
13322            ]);
13323            $this->set( 'threeMillionCampaignStamp', $campaignStamp );
13324            $this->set('showthreeMillionCampAfterLessonModal', true);
13325            $this->set('threeMillionCampSettingId', $threeMillionCampSettingId);
13326        }
13327
13328        // - NJ-65066 【Campaign】Daily Topics
13329        $dailytopicsCamp = array(
13330            'campaign' => 'daily_topics',
13331            'user_membership' => $usrObj->getMembershipTypeIndex(),
13332            'allow_language' => Configure::read('campaign_config.daily_topics.allowed_languages'),
13333            'user_language' => $usrObj->native_language2,
13334            'allow_currency' => Configure::read('campaign_config.daily_topics.allowed_currencies'),
13335            'user_currency' => $usrObj->currency_code,
13336        );
13337        if($cst_->campaignChecker($dailytopicsCamp)){
13338            $dailytopicsCampSettingId = Configure::read('campaign_config.daily_topics.modal_settings.after_lesson');
13339            $campaignStamp = $cst_->dailyTopics([
13340                'trigger' => 1,
13341                'user_id' => $usrObj->id,
13342                'lang' => $this->localizeDir
13343            ]);
13344            $this->set( 'dailytopicsCampaignStamp', $campaignStamp );
13345            $this->set('showdailytopicsCampAfterLessonModal', true);
13346            $this->set('dailytopicsCampSettingId', $dailytopicsCampSettingId);
13347        }
13348        
13349        $this->set('userToken', $this->Auth->user('api_token'));
13350    }
13351
13352
13353    //Determines whether to show the campaign modal based on the current date and the provided start and end dates.
13354    public function showCampaignModal($startDate = null, $endDate = null){
13355        if(!empty($startDate) && !empty($endDate)){
13356            $current_date = strtotime('now');
13357            $showCampaignModal = $current_date >= strtotime($startDate) && $current_date <= strtotime($endDate) ? true : false;
13358
13359            return $showCampaignModal;
13360        }
13361
13362        return false;
13363    }
13364
13365    /**
13366     * @api {post} /user/waiting/generateTextbookTeacherRecommendAjax generateTextbookTeacherRecommendAjax()
13367     * @apiName generateTextbookTeacherRecommendAjax
13368     * @apiGroup Waiting
13369     * @apiDescription Generates a list of recommended teachers for a specific textbook in Native Camp. It retrieves the teacher recommendations based on the user's last lesson and textbook data.
13370     *
13371     * @apiBody {String} category_id The ID of the textbook category.
13372     * @apiBody {String} connect_id The ID of the textbook connect.
13373     * @apiBody {String} teacher_id The ID of the teacher.
13374     * 
13375     * @apiSuccess {Number} result Indicates whether the operation was successful.
13376     * @apiSuccess {String} html The HTML content for the recommended teachers modal.
13377     *
13378     * @apiSuccessExample {json} Success-Response:
13379     *     {
13380     *         "result": 1,
13381     *         "html": "<div>Recommended Teachers</div>"
13382     *     }
13383     *
13384     * @apiError {Number} result Indicates whether the operation was successful.
13385     * @apiError {String} html The HTML content for the recommended teachers modal.
13386     *
13387     * @apiErrorExample {json} Error-Response:
13388     *     {
13389     *         "result": 0,
13390     *         "html": ""
13391     *     }
13392     * 
13393     * @apiSampleRequest off
13394     */
13395    public function generateTextbookTeacherRecommendAjax() {
13396        $this->autoRender = false;
13397        $this->layout = false;
13398        $resultSuccess = 0;
13399        $resultHTML = '';
13400        $isSubmittedFiveStar = 0;
13401        if ($this->request->is('ajax')) {
13402
13403            $curDate = date('Y-m-d');
13404            $userId = $this->Auth->user('id') ? $this->Auth->user('id') : null;
13405            $txtTeacherRecommendlimit = 3; // modal limit
13406            $userData = isset($this->sharedUserData['User']) && $this->sharedUserData['User'] ? $this->sharedUserData['User'] : null;
13407            $endDate = date('Y-m-d',strtotime('-1 day' ,strtotime($curDate)));
13408            $beginDate = date('Y-m-d',strtotime('-1 month' ,strtotime($curDate)));
13409            $categoryId = isset($this->request->data['category_id']) ? $this->request->data['category_id'] : null;
13410            $connectId = isset($this->request->data['connect_id']) ? $this->request->data['connect_id'] : null;
13411            $teacherId = isset($this->request->data['teacher_id']) ? $this->request->data['teacher_id'] : null;
13412            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13413
13414            if( $userId ) {
13415
13416
13417                // - NJ-8416: check for last lesson type
13418                $lastLessonType = ClassRegistry::init('LessonOnair')->getLastLessonType($userId);
13419                $this->log('[NJ-8416 lastLessonType lessonFinish] -> ' . json_encode($lastLessonType), 'debug');
13420                $lastBookUsedData = $this->UsersTextbookInfo->getCurrentTextbookAndBadgeData( array( 
13421                        'user_id' => $userId,
13422                        'connect_id' => $connectId,
13423                        'limit' => 3, // modal
13424                        'last_lesson_type' => $lastLessonType
13425                    ) 
13426                );
13427
13428                $textbookCategoryId = $lastBookUsedData['category_id'];
13429                $textbookBadge = $lastBookUsedData['textbook_badge'];
13430                $this->log('[NJ-8416 textbookCategoryId lessonFinish] -> ' . json_encode($textbookCategoryId), 'debug');
13431                $paramsArr = array(
13432                    'user_id' => $userId,
13433                    'begin_date' => $beginDate,
13434                    'end_date' => $endDate,
13435                    'textbook_category' => $textbookCategoryId,
13436                    'textbook_badge' => $textbookBadge,
13437                    'limit' => $txtTeacherRecommendlimit,
13438                    'user_data' => $userData,
13439                    'exclude_teacher_id' => $teacherId
13440                );
13441
13442                $teacherTextbookStatData = $this->TeacherTextbookStat->fetchTextbookTeacherRatingData($paramsArr);
13443                if( $teacherTextbookStatData ) {
13444                    $dataList = $this->arrangeTeacherRecommendList( array( 
13445                            'user_id' => $userId,
13446                            'data' => $teacherTextbookStatData,
13447                            'category_id' => $textbookCategoryId,
13448                            'user_data' => $userData
13449                        )
13450                    );
13451
13452                    $this->set('textbookTeacherData', $dataList);
13453                    $view = new View($this, false);
13454                    $resultHTML = $view->element( 'lesson_finish_textbook_teacher_list_modal', array(
13455                            'textbookTeacherData' => isset($dataList) && $dataList ? $dataList : array()
13456                        )
13457                    );
13458                    $resultSuccess = 1;
13459                }
13460
13461                //- NJ-61019: get rating from mecached
13462                if($chatHash && $chatHash != 'hash') {
13463                    if (!class_exists('myMemcached')) {
13464                        App::uses('myMemcached', 'Lib');
13465                    }
13466                    $memcached = new myMemcached();
13467                    $rate = $memcached->get("rating_".$chatHash);
13468
13469                    if(isset($rate) && $rate == 5) {
13470                        $isSubmittedFiveStar = 1;
13471                    }
13472                }
13473            }
13474
13475        }
13476        return json_encode(array(
13477            'result' => $resultSuccess,
13478            'html' => $resultHTML,
13479            'isSubmittedFiveStar' => $isSubmittedFiveStar
13480        ));
13481    }
13482
13483    /**
13484    * Ajax Request : fetch user's appreciation options data for modal display
13485    */
13486    //not used function
13487    public function setUpAppreciationSelectionModalElementAjax() {
13488        $this->autoRender = false;
13489        $this->layout = false;
13490        $result = array();
13491        if ($this->request->is('ajax')) {
13492            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : null;
13493            if($chatHash){
13494                $fetchParam = array( 'chat_hash'  => $chatHash );
13495                $fetchedData = $this->setUpAppreciationSelectionModalElement($fetchParam);
13496                if( isset( $fetchedData['html_element'] ) && $fetchedData['html_element'] ){
13497                    $result['html_element'] = $fetchedData['html_element'];
13498                }
13499            }
13500        }
13501        return json_encode(array(
13502            'result' => $result
13503        ));
13504    }
13505
13506    /**
13507    * Ajax Request : Send teacher's appreciation
13508    */
13509    //not used function
13510    public function sendTeacherAppreciationAjax() {
13511        $this->autoRender = false;
13512        $this->layout = false;
13513        $result = array( 'result' => 0 );
13514        $teacherAppreciationMessage = "";
13515        $teacherAppreciationAmount = 0;
13516        $hasTips = 1;
13517        $hasMessage = 1;
13518        $noMessageText = '';
13519        $noTipsText = '';
13520
13521        if ($this->request->is('ajax')) {
13522            $appreciationId = isset($this->request->data['appreciation_ration_input']) ? $this->request->data['appreciation_ration_input'] : null;
13523            $message = isset($this->request->data['user_comment_text']) ? trim($this->request->data['user_comment_text']) : null;
13524            $chatHash = isset($this->request->data['chat_hash_input']) ? $this->request->data['chat_hash_input'] : null;
13525            $actionMode = isset($this->request->data['action_mode']) ? $this->request->data['action_mode'] : 0;
13526            
13527            // - initialize api tunnel
13528            myTools::initializeApiTunnel(array('AppreciationController'));    
13529            $params = array(
13530                "users_api_token" => $this->Auth->user('api_token'),
13531                'chat_hash' => $chatHash,
13532                'appreciation_id'  => $appreciationId,
13533                'message' => $message,
13534                'nc_terminal_type' => Configure::read('nc_terminal_type.pc')
13535
13536            );
13537            $api = new AppreciationController();
13538            $api->params = $params;
13539            
13540            // - send teacher appreciation
13541            $sendData = $api->send();
13542
13543            // - Detect prohibited words in teacher appreciation messages sent after class.
13544            $this->ProhibitedWord->detectProhibitedWordOnStudentAppreciation([
13545                'chat_hash' => $chatHash,
13546                'message' => $message,
13547            ]);
13548            
13549            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13550                // set default res
13551                $result = array( 'result' => 1 );
13552
13553                // set return appreciation item
13554                $appreciationDetails = $sendData['appreciation_item'];
13555
13556            } else {
13557                if( isset ($sendData['error'] ) && $sendData['error'] ){
13558                    $result['error']['id'] = 'sending_failed';
13559                    $result['error']['message'] = json_encode($sendData['error']);
13560                }
13561            }
13562
13563            // set appreciation details student message
13564            if(empty($appreciationDetails['student_message'])){
13565                $appreciationDetails['student_message'] = __d('modal','このお礼にメッセージはありません。');
13566                $appreciationDetails['student_message_flg'] = false;
13567            }else{
13568                $appreciationDetails['student_message_flg'] = true;
13569            }
13570
13571            if ( isset ($sendData['result'] ) && $sendData['result'] ) {
13572                $teacherAppreciationMessage = $appreciationDetails['message'];
13573                $teacherAppreciationAmount = $appreciationDetails['amount'];
13574
13575                if(empty($appreciationId)) {
13576                    // no apprecation tips form
13577                    $hasTips = 0;
13578                    if($appreciationId != 0)  {
13579                        $hasTips = 0;
13580                    }
13581                    $noTipsText = __d('modal','チップはありません');
13582                }
13583
13584                if (empty($message)) {
13585                    // no appreciation message form
13586                    $hasMessage = 0;
13587                    $noMessageText = __d('modal','メッセージはありません');
13588                }
13589
13590                $result = array( 'result' => 1 );
13591
13592                if ($actionMode == 1) {
13593                    $hasTips = 1;
13594                    $hasMessage = 1;
13595                }
13596
13597            } else {
13598                if( isset ($sendData['error'] ) && $sendData['error'] ){
13599                    $result['error']['id'] = 'sending_failed';
13600                    $result['error']['message'] = json_encode($sendData['error']);
13601                    if(isset($sendData['error']['error_code'])) {
13602                        $result['error']['error_code'] = json_encode($sendData['error']['error_code']);
13603                    }
13604                }
13605            }    
13606
13607        }
13608        return json_encode(array(
13609            'output' => $result,
13610            'appreciation_message' => $teacherAppreciationMessage,
13611            'appreciation_amount' => $teacherAppreciationAmount,
13612            'has_tips' => $hasTips,
13613            'has_message' => $hasMessage,
13614            'appreciation_details' => $appreciationDetails,
13615            'no_message_text' => $noMessageText,
13616            'no_tips_text' => $noTipsText
13617        ));
13618    }
13619
13620
13621    /**
13622    * ajax set after lesson evaluate system problem
13623    */
13624    //not used function
13625    public function ajaxUpdateSystemTrouble() {
13626        $this->autoRender = false;
13627        $this->layout = false;
13628        $troubleResponse = false;
13629        if ($this->request->is('ajax')) {
13630            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13631            $status = isset($this->request->data['value']) ? $this->request->data['value'] : 0;
13632            $lesson = $this->LessonOnairsLog->findByChatHash($chatHash, array('LessonOnairsLog.id'),null, -1);
13633            if (isset($lesson) && $lesson) {
13634                if (isset($lesson['LessonOnairsLog']['id']) && $lesson['LessonOnairsLog']['id']) {
13635                    if($this->LessonOnairsLog->read(null, $lesson['LessonOnairsLog']['id'])){
13636                        $this->LessonOnairsLog->saveField('lesson_system_trouble', $status);
13637                    }
13638                    $troubleResponse = true;
13639                }
13640            } 
13641        }
13642        return json_encode(array(
13643            'result' => $troubleResponse
13644        ));
13645    }
13646
13647    /**
13648     * @api {post} /user/waiting/reportProblem reportProblem()
13649     * @apiName reportProblem
13650     * @apiGroup Waiting
13651     * @apiDescription Reports a problem during a lesson in Native Camp. It updates the lesson status and sends a notification to Slack.
13652     *
13653     * @apiBody {String} problem The description of the problem.
13654     * @apiBody {String} chatHash The chat hash of the lesson.
13655     * @apiBody {String} [member_type] The type of the member (viewer or student).
13656     * 
13657     * @apiSuccess {Boolean} success Indicates whether the operation was successful.
13658     *
13659     * @apiSuccessExample {json} Success-Response:
13660     *     {
13661     *         "success": true
13662     *     }
13663     *
13664     * @apiError {Boolean} success Indicates whether the operation was successful.
13665     *
13666     * @apiErrorExample {json} Error-Response:
13667     *     {
13668     *         "success": false
13669     *     }
13670     * 
13671     * @apiSampleRequest off
13672     */
13673    public function reportProblem() {
13674        $this->autoRender = false;
13675        $this->layout = false;
13676
13677        if ($this->Auth->loggedIn() && isset($this->request->data['problem']) && isset($this->request->data['chatHash'])) {
13678            //get data
13679            $problem = $this->request->data['problem'];
13680            $chatHash = $this->request->data['chatHash'];
13681            $userId = $this->Auth->user('id');
13682            $memberType = isset($this->request->data['member_type']) ? $this->request->data['member_type'] : 'student';
13683
13684            if ($memberType == 'viewer') {
13685                //-live_system_trouble
13686                $res = $this->LessonOnairsViewer->updateAll(
13687                    array(
13688                        'LessonOnairsViewer.live_system_trouble' => 1
13689                    ),
13690                    array(
13691                        'LessonOnairsViewer.user_id' => $userId,
13692                        'LessonOnairsViewer.chat_hash' => $chatHash
13693                    )
13694                );
13695                return json_encode(array('success' => ($res?true:false)));
13696            }
13697
13698            $lessonData = LessonOnairTable::findLessonData(array(
13699                'fields' => array(
13700                    'id',
13701                    'teacher_id',
13702                    'user_id',
13703                    'chat_hash',
13704                    'lesson_system_trouble',
13705                    'user_agent'
13706                ),
13707                'conditions' => array(
13708                    'chat_hash' => $chatHash,
13709                    'user_id' => $userId
13710                )
13711            ));
13712
13713            //if no lesson data found
13714            if (!$lessonData) {
13715                return json_encode(array('success' => false));
13716            } elseif ($lessonData['data']['lesson_system_trouble'] == 0) {
13717                //update trouble
13718                $model = ClassRegistry::init($lessonData['model']);
13719                if ($model->read(null, $lessonData['data']['id'])) {
13720                    $model->set('lesson_system_trouble', 1);
13721                    $model->save();
13722                }
13723            }            
13724
13725            //fetch data
13726            $finalData = $lessonData['data'];
13727            $finalData['user_name'] = $this->Auth->user('nickname');
13728
13729            //query teacher name
13730            $teacherData = $this->Teacher->find('first', array(
13731                'fields' => 'name',
13732                'conditions' => array('Teacher.id' => $finalData['teacher_id']),
13733                'recursive' => -1
13734            ));
13735
13736            //set teacher name
13737            $finalData['teacher_name'] = isset($teacherData['Teacher']['name']) ? $teacherData['Teacher']['name'] : ''; 
13738
13739            //fetch problem data
13740            $problemData = $this->LessonOnairsLog->countProblematicLesson(array(
13741                'userId' => $userId,
13742                'teacherId' => $finalData['teacher_id'],
13743                'lessonData' => $lessonData['data']
13744            ));
13745
13746            // send to slack
13747            $slack = new mySlack();
13748            // set the channel, change to #nc-monitoring
13749            $slack->channel  = myTools::checkChannel("#nc-voice-trouble", "#nc-voice-trouble-dev");
13750            //type
13751            $slack->text = "```種別:通信トラブル(PC)\n";
13752            // set os and problem count
13753            $slack->text .= "本日:{$problemData['totalProblemCount']}件目({$problemData['userAgentStr']})\n";
13754            // set lecturer id and number of lesson
13755            $slack->text .= "講師ID:{$finalData['teacher_id']} ({$finalData['teacher_name']})(本日{$problemData['teacherCount']}回目)\n";
13756            // set member id and number of lesson
13757            $slack->text .= "会員ID:{$userId} ({$finalData['user_name']})(本日{$problemData['userCount']}回目)\n";
13758            // set contents
13759            $slack->text .= "内容:{$problem}\n";
13760            // set chat hash
13761            $slack->text .= "chathash: https://{$_SERVER['HTTP_HOST']}/admin/lesson-history?chat_hash={$chatHash}" . '```';
13762            // set slack user name
13763            $slack->username = "NativeCamp";
13764
13765            // send slack
13766            $resp = $slack->sendSlack(); //returns http code
13767            if ($resp) {
13768                return json_encode(array('success' => true));
13769            }
13770        }
13771        return json_encode(array('success' => false));
13772    }
13773
13774    /**
13775     * @api {post} /user/waiting/getApppreciationModal getApppreciationModal()
13776     * @apiName getApppreciationModal
13777     * @apiGroup Waiting
13778     * @apiDescription Retrieves the appreciation modal data for a specific lesson in Native Camp. It checks the appreciation status and returns the appreciation data.
13779     *
13780     * @apiBody {String} chat_hash The chat hash of the lesson.
13781     * @apiBody {String} member_type The type of the member (viewer or student).
13782     * 
13783     * @apiSuccess {Boolean} error Indicates whether there was an error.
13784     * @apiSuccess {String} [error_msg] The error message (if any).
13785     * @apiSuccess {String} [appreciation_data] The HTML element for the appreciation data.
13786     * @apiSuccess {Boolean} [appreciation_done] Indicates whether the appreciation is done.
13787     *
13788     * @apiSuccessExample {json} Success-Response:
13789     *     {
13790     *         "error": false,
13791     *         "appreciation_data": "<div>Appreciation Data</div>",
13792     *         "appreciation_done": true
13793     *     }
13794     *
13795     * @apiError {Boolean} error Indicates whether there was an error.
13796     * @apiError {String} error_msg The error message.
13797     *
13798     * @apiErrorExample {json} Error-Response:
13799     *     {
13800     *         "error": true,
13801     *         "error_msg": "An error occurred."
13802     *     }
13803     * 
13804     * @apiSampleRequest off
13805     */
13806    public function getApppreciationModal() {
13807        $this->autoRender = false;
13808        $this->layout = false;
13809
13810        if ($this->request->is('ajax')) {
13811            $response = array();
13812            $data = $this->request->data;
13813
13814            try  {
13815                if (!empty($data['member_type']) && $data['member_type'] !== 'viewer') {
13816                    // Check appreciation data
13817                    $appreciationElementData = $this->setUpAppreciationSelectionModalElement( array( 'chat_hash' => $data['chat_hash'] ) );
13818                    if(!empty($appreciationElementData['html_element'])){
13819                        $response['appreciation_data'] = $appreciationElementData['html_element'];
13820                    }
13821                    $elapsed5mins = false;
13822                    // 5mins elapsed only
13823                    $lessonExists = $this->LessonOnairsLog->isLessonEnded($data['chat_hash']);
13824                    if ($lessonExists) {
13825                        $this->LessonOnairsLog->openDBReplica();
13826                        $created = $this->LessonOnairsLog->find('first', [
13827                            'fields' => ['created'],
13828                            'conditions' => ['chat_hash' => $data['chat_hash']]
13829                        ]);
13830                        $this->LessonOnairsLog->closeDBReplica();
13831                        if (!empty($created)){
13832                            $created = $created['LessonOnairsLog']['created'];
13833                            $now = date('Y-m-d H:i:s');
13834                            $elapsed5mins = ( strtotime($now) - strtotime($created)) > 300;
13835                        }
13836                    }
13837                    $response['has_elapsed'] = $elapsed5mins;
13838                    $response['appreciation_done'] = $this->getAppreciationStatus($data['chat_hash']);
13839                    $response['error'] = false;
13840                }
13841                return json_encode($response);
13842                
13843            } catch (Exception $e) {
13844                $response['error'] = true;
13845                $response['error_msg'] = $e->getMessage();
13846
13847                 // - add logger
13848                 $mySlack = new mySlack();
13849                 $mySlack->channel = myTools::checkChannel("#fdci-irregular-monitoring");
13850                 $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
13851                 $mySlack->username = "GetAppreciationModalFailed";
13852                 $mySlack->text = "```";
13853                 $mySlack->text .= "Message : ". $e->getMessage() ."\n";
13854                 $mySlack->text .= "Chat-hash: ". $data['chat_hash'] ."\n";
13855                 $mySlack->text .= "Student ID: ". $this->Auth->user('id') ."\n";
13856                 $mySlack->text .= "UA: ". $_SERVER['HTTP_USER_AGENT'] ."\n";
13857                 $mySlack->text .= "referrer: ". $_SERVER['HTTP_REFERER'] ."\n";
13858                 $mySlack->text .= "```";
13859                 // - send slack message
13860                 $mySlack->sendSlack();
13861                return json_encode($response);
13862            }
13863        }
13864    }
13865
13866    private function getAppreciationStatus($chatHash) {
13867        $doneAppreciation = false;
13868        $appreFields = array(
13869            'TeacherCoinBox.has_tips',
13870            'TeacherCoinBox.done_flg'
13871        );
13872        $checkCoinBoxData = $this->TeacherCoinBox->getData(array('chat_hash' => $chatHash), $appreFields);
13873        if(
13874            $checkCoinBoxData && 
13875            (isset($checkCoinBoxData['TeacherCoinBox']['has_tips']) && $checkCoinBoxData['TeacherCoinBox']['has_tips']) ||
13876            (isset($checkCoinBoxData['TeacherCoinBox']['done_flg']) && $checkCoinBoxData['TeacherCoinBox']['done_flg'])
13877        ) {
13878            $doneAppreciation = true;
13879        }
13880
13881        return $doneAppreciation;
13882    }
13883
13884    /**
13885     * @api {post} /user/waiting/getEvaluationDetail getEvaluationDetail()
13886     * @apiName getEvaluationDetail
13887     * @apiGroup Waiting
13888     * @apiDescription Retrieves the evaluation detail for a specific lesson in Native Camp. It checks if the user has already submitted an evaluation for the lesson.
13889     *
13890     * @apiBody {String} chat_hash The chat hash of the lesson.
13891     * @apiBody {String} [member_type] The type of the member (viewer or student).
13892     * 
13893     * @apiSuccess {Boolean} status Indicates whether the evaluation has been submitted.
13894     *
13895     * @apiSuccessExample {json} Success-Response:
13896     *     {
13897     *         "status": true
13898     *     }
13899     *
13900     * @apiError {String} error Message indicating the error.
13901     *
13902     * @apiErrorExample {json} Error-Response:
13903     *     {
13904     *         "error": "Invalid request."
13905     *     }
13906     * 
13907     * @apiSampleRequest off
13908     */
13909    public function getEvaluationDetail() {
13910        $this->autoRender = false;
13911        $this->layout = false;
13912        $doneReview['status'] = false;
13913        if ($this->request->is('ajax')) {
13914            $chatHash = isset($this->request->data['chat_hash']) ? $this->request->data['chat_hash'] : '';
13915            //-check if viewer
13916            if (isset($this->request->data['member_type']) && $this->request->data['member_type'] == 'viewer') {
13917                $eval = $this->ViewersClassEvaluation->find('first', [
13918                    'conditions' => [
13919                        'ViewersClassEvaluation.user_id' => $this->Auth->user('id'),
13920                        'ViewersClassEvaluation.chat_hash' => $chatHash
13921                    ]
13922                ]);
13923                $doneReview['status'] = !empty($eval);        
13924            } else {
13925                if ($this->UsersClassEvaluation->findByChatHash($chatHash)) {
13926                    $doneReview['status'] = true;
13927                }
13928            }
13929        }
13930        return json_encode($doneReview);
13931    }
13932    /**
13933     * @api {post} /user/waiting/resetLessonReviewModal resetLessonReviewModal()
13934     * @apiName resetLessonReviewModal
13935     * @apiGroup Waiting
13936     * @apiDescription Resets the lesson review modal status for a specific lesson and user in Native Camp. It deletes the modal status from the cache.
13937     *
13938     * @apiBody {String} chatHash The chat hash of the lesson.
13939     * @apiBody {String} userId The ID of the user.
13940     * 
13941     * @apiSuccess {Boolean} res Indicates whether the operation was successful.
13942     *
13943     * @apiSuccessExample {json} Success-Response:
13944     *     {
13945     *         "res": true
13946     *     }
13947     *
13948     * @apiError {String} error Message indicating the error.
13949     *
13950     * @apiErrorExample {json} Error-Response:
13951     *     {
13952     *         "error": "Invalid request."
13953     *     }
13954     * 
13955     * @apiSampleRequest off
13956     */
13957    public function resetLessonReviewModal() {
13958        $this->autoRender = false;
13959        $this->layout = false;
13960        if ($this->request->is('ajax')) {
13961            $chatHash = $this->request->data('chatHash');
13962            $userId = $this->request->data('userId');
13963            $memcached = new myMemcached();
13964            $modalStatus = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $userId);
13965            if ($modalStatus !== false) {
13966                $memcached->delete('lesson-review-modal-' . $chatHash .'-'. $userId);
13967            }
13968        }
13969        echo json_encode(array('res' => true));
13970    }
13971
13972    /**
13973     * @api {post} /user/waiting/finishOnlineLesson finishOnlineLesson()
13974     * @apiName finishOnlineLesson
13975     * @apiGroup Waiting
13976     * @apiDescription Finishes an online lesson for the authenticated user in Native Camp. It retrieves lesson details, updates lesson status, and returns the lesson summary.
13977     *
13978     * @apiBody {String} chatHash The chat hash of the lesson.
13979     * 
13980     * @apiSuccess {Boolean} lessonHistoryExist Indicates whether the lesson history exists.
13981     * @apiSuccess {String} ageRange The age range of the user.
13982     * @apiSuccess {Object} logDetail The lesson log details.
13983     * @apiSuccess {Object} lessonOnAirData The lesson on-air data.
13984     * @apiSuccess {Object} teacherDetailData The teacher detail data.
13985     * @apiSuccess {Object} teacherData The teacher data.
13986     * @apiSuccess {Array} avatarTeacherIdArr The array of avatar teacher IDs.
13987     * @apiSuccess {String} teacherName The name of the teacher.
13988     * @apiSuccess {String} teacherNameJA The Japanese name of the teacher.
13989     * @apiSuccess {String} teacherImage The image URL of the teacher.
13990     * @apiSuccess {String} urlLink The URL link to the teacher's detail page.
13991     * @apiSuccess {String} favTeaherId The favorite teacher ID.
13992     * @apiSuccess {String} counselorImageUrl The image URL of the counselor.
13993     * @apiSuccess {String} textbookImage The image URL of the textbook.
13994     * @apiSuccess {String} courseTitle The title of the course.
13995     * @apiSuccess {String} subCategoryLabel The label of the subcategory.
13996     * @apiSuccess {String} chapterTitle The title of the chapter.
13997     * @apiSuccess {Boolean} lessonTrouble Indicates whether there was a lesson trouble.
13998     * @apiSuccess {String} userToken The user token.
13999     * @apiSuccess {Object} finishLessonUser The user data.
14000     * @apiSuccess {String} chat_hash The chat hash of the lesson.
14001     * @apiSuccess {Boolean} lesson_review_flg Indicates whether the lesson review flag is set.
14002     * @apiSuccess {Boolean} isDefaulTextbook Indicates whether the textbook is the default textbook.
14003     * @apiSuccess {Boolean} firstSelectedDummy Indicates whether the first selected textbook is a dummy.
14004     * @apiSuccess {Boolean} allowEvaluation Indicates whether the teacher evaluation is allowed.
14005     * @apiSuccess {Object} getActiveCampaign The active campaign data.
14006     * @apiSuccess {Boolean} firstLesson Indicates whether it is the first lesson.
14007     * @apiSuccess {Boolean} hideTextbookChangeModal Indicates whether to hide the textbook change modal.
14008     * @apiSuccess {String} textbookCategoryType The type of the textbook category.
14009     * @apiSuccess {String} memberType The type of the member.
14010     * @apiSuccess {String} nickname The nickname of the user.
14011     * @apiSuccess {Number} textbookCategoryId The ID of the textbook category.
14012     * @apiSuccess {Number} isLiveFlg Indicates whether the lesson is live.
14013     * @apiSuccess {Boolean} lessonReviewModalOn Indicates whether the lesson review modal is on.
14014     * @apiSuccess {String} user_language The language of the user.
14015     *
14016     * @apiSuccessExample {json} Success-Response:
14017     *     {
14018     *         "lessonHistoryExist": true,
14019     *         "ageRange": "20-30",
14020     *         "logDetail": {...},
14021     *         "lessonOnAirData": {...},
14022     *         "teacherDetailData": {...},
14023     *         "teacherData": {...},
14024     *         "avatarTeacherIdArr": [...],
14025     *         "teacherName": "John Doe",
14026     *         "teacherNameJA": "ジョン・ドウ",
14027     *         "teacherImage": "http://example.com/image.jpg",
14028     *         "urlLink": "/waiting/detail/1",
14029     *         "favTeaherId": "1",
14030     *         "counselorImageUrl": "http://example.com/counselor.jpg",
14031     *         "textbookImage": "http://example.com/textbook.jpg",
14032     *         "courseTitle": "Course Title",
14033     *         "subCategoryLabel": "Subcategory Label",
14034     *         "chapterTitle": "Chapter Title",
14035     *         "lessonTrouble": false,
14036     *         "userToken": "example_token",
14037     *         "finishLessonUser": {...},
14038     *         "chat_hash": "example_chat_hash",
14039     *         "lesson_review_flg": 1,
14040     *         "isDefaulTextbook": false,
14041     *         "firstSelectedDummy": false,
14042     *         "allowEvaluation": 1,
14043     *         "getActiveCampaign": {...},
14044     *         "firstLesson": false,
14045     *         "hideTextbookChangeModal": "false",
14046     *         "textbookCategoryType": "Type",
14047     *         "memberType": "student",
14048     *         "nickname": "nickname",
14049     *         "textbookCategoryId": 1,
14050     *         "isLiveFlg": 0,
14051     *         "lessonReviewModalOn": false,
14052     *         "user_language": "en"
14053     *     }
14054     *
14055     * @apiError {String} error Message indicating the error.
14056     *
14057     * @apiErrorExample {json} Error-Response:
14058     *     {
14059     *         "error": "Invalid request."
14060     *     }
14061     * 
14062     * @apiSampleRequest off
14063     */
14064    public function finishOnlineLesson() {
14065        $this->autoRender = false;
14066        $this->layout = false;
14067        if ($this->request->is('ajax')) {
14068            $chatHash = $this->request->data('chatHash');
14069        
14070            // 4372 textbook name cached
14071            $memcached = new myMemcached();
14072            $textbookNamesCached = $memcached->get(Configure::read('textbook_names_cache_key'));
14073
14074            $userId = $this->Auth->user('id');
14075            $this->Session->delete('lesson.proceedFlg');
14076            //CheckHash
14077            $this->LessonOnairsLog->openDBReplica();
14078            $allData = $this->LessonOnairsLog->find('first', $this->checkHash('LessonOnairsLog',$chatHash));
14079            $lessonHistoryExist = true;
14080            $this->LessonOnairsLog->closeDBReplica();
14081            if(!$allData) { // if LessonOnairsLog's chat_hash returns null/empty , retrieve record from lessonOnair
14082                $this->LessonOnair->openDBReplica();
14083                $allData = $this->LessonOnair->find('first', $this->checkHash('LessonOnair',$chatHash));
14084                $lessonHistoryExist = false;
14085                $this->LessonOnair->closeDBReplica();
14086                if(!$allData) {
14087                    die();
14088                }
14089            }
14090
14091            $response['lessonHistoryExist'] = $lessonHistoryExist;
14092            $userValidForSSBEDT = false;
14093            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14094                $userValidForSSBEDT = true;
14095            }
14096
14097            $param = array( 
14098                "user_id" => $userId,
14099                "select_method" => "first",
14100                "env_flag" => "all",
14101                'connect_id' => $allData['Connect']['id'],
14102                "user_locale" => $this->localizeDir,
14103                "userValidForSSBEDT" => $userValidForSSBEDT
14104            );
14105            $textbookData = $this->Textbook->getTextbooks($param);
14106            
14107            $lessonUserData = (isset($allData['User'])) ? new UserTable($allData['User']) : null;
14108            
14109            $response['ageRange'] = $lessonUserData->getAgeRange();
14110            $response['logDetail'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14111            if(isset($allData['LessonOnairsLog'])) {
14112                $response['lessonOnAirData'] = new LessonOnairsLogTable($allData['LessonOnairsLog']);
14113
14114            } else if(isset($allData['LessonOnair'])) {
14115                $response['lessonOnAirData'] = new LessonOnairTable($allData['LessonOnair']);
14116            } else {
14117                $response['lessonOnAirData'] = null;
14118            }
14119            $teacherData = new TeacherTable($allData['teacher']);
14120            $response['teacherDetailData'] = new TeacherDetailTable($allData['TeacherDetail']);
14121            
14122            $response['teacherData'] = $teacherData;
14123            $response['avatarTeacherIdArr'] = Configure::read("default_avatar_detail");
14124            $response['teacherName'] = $teacherData->name;
14125            $response['teacherNameJA'] = $teacherData->jp_name;
14126            $response['teacherImage'] = $teacherData->getImageUrl();
14127            $response['urlLink'] = "/waiting/detail/".$teacherData->getId();
14128            $response['favTeaherId'] = $teacherData->id;
14129            if ($teacherData->counseling_flg) {
14130                $counselorImageUrl = $teacherData->getProfileImage(Configure::read('default_counselor_detail'));
14131                $response['counselorImageUrl'] = $counselorImageUrl;
14132                $response['teacherName'] = "Counselor";
14133                $response['teacherNameJA'] = "カウンセラー";
14134                $response['teacherImage'] = $counselorImageUrl['image_url'];
14135                $response['urlLink'] = "/counselor_detail";
14136            }
14137            // avatar teacher
14138            if ($teacherData->avatar_id && $teacherData->avatar_flg) {
14139                if ($teacherData->avatar_id) {
14140                    $response['teacherName'] = $teacherData->getAvatarParentNameEn();
14141                    $response['teacherNameJA'] =  $teacherData->getAvatarParentName();
14142                    $response['teacherImage'] = $teacherData->getAvatarParentImageUrl();
14143                    $response['favTeaherId'] = $teacherData->avatar_id;
14144                    $response['urlLink'] = "/avatar_detail/".$teacherData->avatar_id;
14145                }
14146            }
14147
14148            $data = $textbookData['res_data'];
14149            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14150
14151            //- check if for live viewing
14152            $onairData = isset($allData['LessonOnairsLog']) ? $allData['LessonOnairsLog'] : $allData['LessonOnair'];
14153            $onAirUserId = $onairData['user_id'];
14154            $isLive = $onairData['live_lesson_flg'];
14155
14156            //- check member type
14157            $memberType = 'student';
14158            $liveSystemTrouble = 0;
14159
14160            if ($isLive && $onAirUserId != $userId) {
14161                $memberType = 'viewer';
14162                //- update end time
14163                $this->LessonOnairsViewersLog->endTime([
14164                    'chat_hash'     => $chatHash,
14165                    'user_id'         => $userId,
14166                    'guest_viewer'     => empty($userId) ? 1 : 0,
14167                    'viewer_ip'         => myTools::getClientIP()
14168                ]);
14169
14170                $liveLog = $this->LessonOnairsViewer->find('first', [
14171                    'fields' => [
14172                        'LessonOnairsViewer.live_system_trouble'
14173                    ],
14174                    'conditions' => [
14175                        'LessonOnairsViewer.user_id' => $userId,
14176                        'LessonOnairsViewer.chat_hash' => $chatHash
14177                    ]
14178                ]);
14179                $liveSystemTrouble = (!empty($liveLog['LessonOnairsViewer']['live_system_trouble'])) ? 1 : 0;
14180
14181                if ($liveLog) {
14182                    // process live lesson coupon grant
14183                    $this->LessonOnairsViewer->processLiveLessonCouponGrant($this->sharedUserData['User'], $chatHash);
14184                }
14185            }
14186
14187            $userValidForSSBEDT = false;
14188            if (isset($this->localizeDir) && $this->localizeDir == Configure::read('default.user_language')){
14189                $userValidForSSBEDT = true;
14190            }
14191            $param = array(
14192                "user_id" => $userId,
14193                "select_method" => "first",
14194                "env_flag" => "all",
14195                'connect_id' => $allData['Connect']['id'],
14196                "user_locale" => $this->localizeDir,
14197                "userValidForSSBEDT" => $userValidForSSBEDT
14198            );
14199            //NJ-12326
14200            if ($userId && isset($allData['Connect']['category_id']) && $allData['Connect']['category_id']) {
14201                $corporateParams = array('user_id' => $userId);
14202                $corporateTextbookControlFlg = $this->Corporate->getCorporateTextbookControl($corporateParams);
14203
14204                if ($corporateTextbookControlFlg == 1) {
14205                    $categoryData = $this->TextbookCategory->getKidsCategoryTypesById($allData['Connect']['category_id']);
14206                    if (!empty($categoryData)) {
14207                        $param['include_kids_category'] = $allData['Connect']['category_id'];
14208                    }
14209                }
14210            }
14211            $textbookData = $this->Textbook->getTextbooks($param);
14212
14213            $data = $textbookData['res_data'];
14214
14215            // textbook image
14216            $response['textbookImage'] = $data['TextbookCategory']['image_small_url'];
14217
14218            $order = (isset($textbookNamesCached[$data['TextbookConnect']['id']]['order']) && $textbookNamesCached[$data['TextbookConnect']['id']]['order']) ? $textbookNamesCached[$data['TextbookConnect']['id']]['order'] : '';
14219            
14220            $courseTitle = (isset($data['TextbookCategory']['name'])) ? $data['TextbookCategory']['name'] : '';
14221            $subCategoryNameLabel = (isset($data['TextbookSubcategory']['name'])) ? $data['TextbookSubcategory']['name'] : '';
14222            $chapterTitle = isset($textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] ) ?  $textbookNamesCached[$data['TextbookConnect']['id']]['jpn'] : ((isset($data['Textbook']['name'])) ? $order.$data['Textbook']['name'] : '');
14223
14224            #global textbook information
14225            $globalCourseTitle = isset($data['GlobalTextbookCategory']['gl_name']) ? $data['GlobalTextbookCategory']['gl_name'] : $courseTitle;
14226            $subCategoryNameLabel = isset($data['GlobalTextbookSubcategory']['gl_name']) ? $data['GlobalTextbookSubcategory']['gl_name'] : $subCategoryNameLabel;
14227            $globalChapterTitle = isset($data['GlobalTextbook']['gl_name']) ? $order.$data['GlobalTextbook']['gl_name'] : $chapterTitle;
14228
14229            // check for main topic
14230            if ( isset($data['Textbook']['main_topic_id']) && $data['Textbook']['main_topic_id'] ) {
14231                $langId = ClassRegistry::init('CountryCode')->getUserLanguageId($this->localizeDir);
14232                $textbookMainTopicName = ClassRegistry::init('Textbook')->getTextbookMainTopicName($data['Textbook']['id'],$langId);
14233                if ($textbookMainTopicName) {
14234                    $subCategoryNameLabel = $textbookMainTopicName;
14235                }
14236            }
14237
14238            //get teacher id from logs
14239            $teacherId = isset($allData['LessonOnairsLog']['teacher_id']) ? $allData['LessonOnairsLog']['teacher_id'] : $allData['LessonOnair']['teacher_id']; 
14240
14241            // - check if the queried data has teacher rank coin id
14242            if(isset($allData['teacher']['rank_coin_id'])) {
14243                $teacher_rank_coin_id = $allData['teacher']['rank_coin_id'];
14244
14245            } else {
14246                // - get teacher rank coin id
14247                $this->Teacher->openDBReplica();
14248                $coinId = $this->Teacher->find('first',array(
14249                    'fields' => array('Teacher.rank_coin_id'),
14250                    'conditions' => array('Teacher.id' => $teacherId),
14251                    'recursive' => -1
14252                ));
14253                $this->Teacher->closeDBReplica();
14254                $teacher_rank_coin_id = isset($coinId['Teacher']['rank_coin_id']) ? $coinId['Teacher']['rank_coin_id'] :  null;
14255
14256            }
14257
14258            $showRatingFlg = $this->TeacherRankCoin->find('first',array(
14259                    'fields' => array('TeacherRankCoin.strength_weakness_flag', 'TeacherRankCoin.id'),
14260                    'conditions' => array('TeacherRankCoin.id' => $teacher_rank_coin_id)
14261                ));
14262            $response['showRatingFlg'] = $showRatingFlg['TeacherRankCoin']['strength_weakness_flag'];
14263
14264            $user = (isset($this->sharedUserData['User'])) ? new UserTable($this->sharedUserData['User']) : null;
14265            $response['userMembershipIndex'] = null;
14266            if (!empty($user)) {
14267                $userMembershipIndex = $user->getMembershipTypeIndex();
14268                $response['userMembershipIndex'] = $userMembershipIndex;
14269            }            
14270
14271            $noNextTextbookModal = array(
14272                11, //'Corporate Limited Plan(Company payment-Bank transfer)'
14273                35, //'Study Sapuri ENGLISH School Plan (Paid)',
14274                16, //'Corporate Light Plan(Company payment-Bank transfer)',
14275                25, //'Corporate Light Plan (Company payment-Card)',
14276                17, //'Corporate Light Plan (Individual payment)',
14277            );
14278
14279            $response['noNextTextbookModal'] = $noNextTextbookModal;
14280
14281            $counselorDetail = $this->Teacher->getDefaultCounselorDetail();
14282            $this->set('counselorDetail', $counselorDetail);
14283
14284            if (is_null($allData['teacher']['first_lesson_date'])) {
14285                if (isset($allData['LessonOnair'])) {
14286                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnair']['end_time'];
14287                } elseif (isset($allData['LessonOnairsLog'])) {
14288                    $allData['teacher']['first_lesson_date'] = $allData['LessonOnairsLog']['end_time'];
14289                }
14290            }
14291
14292            //NC-4572
14293            $userID = $this->Auth->user('id');
14294
14295            $lessonTrouble = isset($allData['LessonOnairsLog']['lesson_system_trouble']) ? intval($allData['LessonOnairsLog']['lesson_system_trouble']) : intval($allData['LessonOnair']['lesson_system_trouble']); 
14296
14297            $response['lessonTrouble'] =  ($lessonTrouble || $liveSystemTrouble);
14298            $response['userToken'] = $this->Auth->user('api_token');
14299            $response['courseTitle'] = $globalCourseTitle;
14300            $response['subCategoryLabel'] = $subCategoryNameLabel;
14301            $response['chapterTitle'] = $globalChapterTitle;
14302            $response['finishLessonUser'] = $user;
14303            $response['chat_hash'] = $chatHash;
14304            $response['lesson_review_flg'] = isset($user->lesson_review_flg) ? $user->lesson_review_flg : 0;
14305
14306            // NJ-8416
14307            $env = Configure::read('ENVIRONMENT');
14308            $defaultTextbookId = Configure::read("default_dummy_textbook.{$env}");
14309            $dummyConnectId = Configure::read("dummy_textbook_connect_id.{$env}");
14310
14311            // - check end lesson textbook is dummy
14312            $isDefaulTextbook = ($defaultTextbookId == $allData['Connect']['category_id']) ? true : false;
14313
14314            $response['isDefaulTextbook'] = $isDefaulTextbook;
14315
14316            // - get first selected textbook connect_id
14317            $userFirstSelectedTextbook = $this->User->getUserData(
14318                array(
14319                    'id' => $userId
14320                ),
14321                array(
14322                    'first_selected_textbook'
14323                ),
14324                'first'
14325            );
14326
14327            // - check first selected textbook connect_id is dummy
14328            $firstSelectedDummy = ($userFirstSelectedTextbook['User']['first_selected_textbook'] == $dummyConnectId) ? true : false;
14329            $response['firstSelectedDummy'] = $firstSelectedDummy;
14330
14331
14332            // NJ-33170
14333            $lessonConnectId = isset($allData['LessonOnairsLog']['connect_id']) && $allData['LessonOnairsLog']['connect_id'] ? $allData['LessonOnairsLog']['connect_id'] : $allData['LessonOnair']['connect_id'];
14334            // get lesson textbook category id
14335            $this->TextbookConnect->openDbReplica();
14336            $textbookConnect = $this->TextbookConnect->find('first', array(
14337                'fields' => array('TextbookConnect.category_id'),
14338                'conditions' => array('TextbookConnect.id' => $lessonConnectId)
14339            ));
14340            $this->TextbookConnect->closeDbReplica();
14341            $lessonTextbookCategoryId = isset($textbookConnect['TextbookConnect']['category_id']) ? $textbookConnect['TextbookConnect']['category_id'] : null;
14342            
14343            $teacherEvalRestrictedTextbook = Configure::read("teacher_evaluation_restricted_textbook.{$env}");
14344            // disable teacher textbook evaluation if textbook is: (Textbook selection after entering the lesson)
14345            $allowEvaluation = $lessonTextbookCategoryId == $teacherEvalRestrictedTextbook ? 0 : 1;
14346
14347            $response['allowEvaluation'] = $allowEvaluation;
14348
14349            // [START]--- Campaign modal
14350            $getActiveCampaignParams = array(
14351                'counseling_flg' => isset($allData['teacher']['counseling_flg']) ? $allData['teacher']['counseling_flg'] : 0,
14352                'avatar_flg' => isset($allData['teacher']['avatar_flg']) ? $allData['teacher']['avatar_flg'] : 0,
14353                'chat_hash' => $chatHash,
14354                'memberType' => $memberType
14355            );
14356            $response['getActiveCampaign'] = $this->getActiveCampaign($getActiveCampaignParams);
14357            // [ END ]--- Campaign modal
14358
14359            // NC-7922 sapuri first lesson
14360            if ($this->studySapuriId) {
14361                $firstLesson = $this->UserFirstLesson->checkFirstLesson(array('user_id' => $userID));
14362                if ($firstLesson && $firstLesson['UserFirstLesson']['chat_hash'] == $chatHash) {
14363                    $oUserData = new UserTable($this->sharedUserData['User']);
14364                    $sapuriPlan = $oUserData->isStudySapuri();
14365                    $stusapTextType = Configure::read('studysapuri_textbook_category_types');
14366                    $topList = $this->CommonTeacherStatus->getSapuriRecommendTeacher($stusapTextType[$sapuriPlan]);
14367                    $firstLesson = true;
14368
14369                    $response['reserveRecommend'] = $topList;
14370                } else {
14371                    $firstLesson = false;
14372                }
14373            } else {
14374                $firstLesson = false;
14375            }
14376
14377            $response['firstLesson'] = $firstLesson;
14378
14379            // NC-7592 - Hide textbookChange modal after lesson if reserved lesson & disable button if no next textbook chapter
14380            $isReservedLesson = 2;
14381            $hideTextbookChangeModal = $enableNextTextbookChapterButton = 'false';
14382            $latestPresetTextbookConnect_id = (int)$data['TextbookConnect']['id'];
14383
14384            //NJ-3626 Optimize PC /lesson-finish page
14385            $lessonOnairLatestData = $this->LessonOnair->getLatestLessonOnairDetailsOfUserAndTeacher($userId, $teacherId);
14386            $lessonOnairLatestDataFlg = false;
14387            if(isset($lessonOnairLatestData) && $lessonOnairLatestData) {
14388                $lessonOnairLatestDataFlg = true;
14389                $lessonOnairLatest_connectId = (int)$lessonOnairLatestData['LessonOnair']['connect_id'];
14390                $lessonOnairLatest_lessonType = (int)$lessonOnairLatestData['LessonOnair']['lesson_type'];
14391            } else {
14392                $lessonOnairLogsLatestData = $this->LessonOnairsLog->getLatestLessonLogsDetailsOfUserAndTeacher($userID, $teacherId);
14393                if(isset($lessonOnairLogsLatestData) && $lessonOnairLogsLatestData) {
14394                    $lessonOnairLogsLatest_connectId = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['connect_id'];
14395                    $lessonOnairLogsLatest_lessonType = (int)$lessonOnairLogsLatestData['LessonOnairsLog']['lesson_type'];
14396                }
14397            }
14398
14399            // - initialize empty variable
14400            $isLatestPresetTextbookMadeDuringLastLesson = [];
14401            $latestPresetTextbookParams = [];
14402
14403            // For hiding of textbookchange modal (if reserved lesson & not studySapuri)
14404            if ($lessonOnairLatestDataFlg) {
14405                $latestPresetTextbookParams = array (
14406                    'userId' => $userID,
14407                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14408                    'lessonOnairLatest_startTime' => $lessonOnairLatestData['LessonOnair']['start_time'],
14409                    'lessonOnairLatest_endTime' => $lessonOnairLatestData['LessonOnair']['end_time']
14410                );
14411
14412            // - if has lesson onairs log
14413            } else if ($lessonOnairLogsLatestData) {
14414                $latestPresetTextbookParams = array (
14415                    'userId' => $userID,
14416                    'latestPresetTextbookConnect_id' => $latestPresetTextbookConnect_id,
14417                    'lessonOnairLogsLatest_startTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['start_time'],
14418                    'lessonOnairLogsLatest_endTime' => $lessonOnairLogsLatestData['LessonOnairsLog']['end_time']
14419                );
14420
14421            }
14422
14423            $response['isStudySapuriTosUser'] = $this->isStudySapuriTosUser;
14424            // - if has parameters for fetching latest textbook parameters
14425            if ($latestPresetTextbookParams) {
14426                $isLatestPresetTextbookMadeDuringLastLesson = $this->UsersTextbookInfo->checkLatestUserTextbookInfoChangedDuringLesson($latestPresetTextbookParams);
14427            }
14428
14429            // -  check sapuri ID
14430            if(!isset($this->studySapuriId) || !$this->studySapuriId) {
14431                if (isset($lessonOnairLatestDataFlg)) {
14432                    if (is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14433                        && $latestPresetTextbookConnect_id == $lessonOnairLatest_connectId && $lessonOnairLatest_lessonType == $isReservedLesson
14434                    ) {
14435                        $hideTextbookChangeModal = 'true';
14436                    }
14437                } else {
14438                    if (
14439                        is_array($isLatestPresetTextbookMadeDuringLastLesson) && !empty($isLatestPresetTextbookMadeDuringLastLesson)
14440                        && $latestPresetTextbookConnect_id == $lessonOnairLogsLatest_connectId &&  $lessonOnairLogsLatest_lessonType == $isReservedLesson
14441                    ) {
14442                        $hideTextbookChangeModal = 'true';
14443                    }
14444                }
14445            }
14446            
14447            // NJ-3696
14448            if($lessonHistoryExist) {
14449                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnairsLog']['textbook_category_id']);
14450            } else {
14451                $response['textbookCategoryType'] = $this->TextbookCategory->getTextbookCategoryType($allData['LessonOnair']['textbook_category_id']);
14452            }
14453
14454            //TODO: NJ-59368 - send is callan textbook category
14455            $response['isCallanTextbook'] = in_array($response['textbookCategoryType'], Configure::read('callan_textbook_type'));
14456
14457            $response['hideTextbookChangeModal'] = $hideTextbookChangeModal;
14458
14459            $response['memberType'] = $memberType;
14460            $response['nickname'] = isset($this->sharedUserData['User']['nickname']) ? $this->sharedUserData['User']['nickname'] : $this->Auth->user('nickname');
14461            $response['textbookCategoryId'] = (int)$allData['Connect']['category_id'];
14462            $response['isLiveFlg'] = (int)$isLive;
14463            $response['lessonReviewModalOn'] = false;
14464            $response['network_review_flg'] = $this->sharedUserData['User']['network_review_flg']; // include the user's setting 'network_review_flg' in the response
14465            if ($this->Auth->User('id')) {
14466                $reviewLessonCache = $memcached->get('lesson-review-modal-'. $chatHash .'-'. $this->Auth->User('id'));
14467                if ($reviewLessonCache !== false && $reviewLessonCache == 1) {
14468                    $response['lessonReviewModalOn'] = true;
14469                }
14470            }
14471            $response['user_language'] = $this->localizeDir;
14472            return json_encode($response);
14473        }
14474        
14475    }
14476
14477    /**
14478     * @api {post} /user/waiting/getCounselorLessonHistory getCounselorLessonHistory()
14479     * @apiName getCounselorLessonHistory
14480     * @apiGroup Waiting
14481     * @apiDescription Retrieves the lesson history for a specific counselor in Native Camp. It returns the lesson history details including textbook information, lesson time, and URLs for chat logs and message logs.
14482     *
14483     * @apiBody {String} teacherId The ID of the teacher.
14484     * 
14485     * @apiSuccess {Boolean} res Indicates whether the request was successful.
14486     * @apiSuccess {Array} lessonHistory The lesson history details.
14487     * @apiSuccess {String} lessonHistory.lesson_number The lesson number.
14488     * @apiSuccess {String} lessonHistory.chatStartJPDate The start date of the chat in Japanese format.
14489     * @apiSuccess {String} lessonHistory.chatStartTime The start time of the chat.
14490     * @apiSuccess {String} lessonHistory.lessonHistoryTime The duration of the lesson in minutes.
14491     * @apiSuccess {String} lessonHistory.textbook_url The URL for the textbook details.
14492     * @apiSuccess {String} lessonHistory.categoryNameLabel The label for the category name.
14493     * @apiSuccess {String} lessonHistory.subCategoryNameLabel The label for the subcategory name.
14494     * @apiSuccess {String} lessonHistory.textbookNameLabel The label for the textbook name.
14495     * @apiSuccess {Number} lessonHistory.rate The rating for the lesson.
14496     * @apiSuccess {String} lessonHistory.chat_logs_url The URL for the chat logs.
14497     * @apiSuccess {Boolean} lessonHistory.has_message_logs Indicates whether the lesson has message logs.
14498     * @apiSuccess {String} lessonHistory.message_logs_url The URL for the message logs.
14499     * @apiSuccess {Number} lessonHistory.audio_count_log The audio count log.
14500     * @apiSuccess {String} lessonHistory.textbook_image The URL for the textbook image.
14501     *
14502     * @apiSuccessExample {json} Success-Response:
14503     *     {
14504     *         "res": true,
14505     *         "lessonHistory": [
14506     *             {
14507     *                 "lesson_number": "1",
14508     *                 "chatStartJPDate": "2023-01-01",
14509     *                 "chatStartTime": "10:00",
14510     *                 "lessonHistoryTime": "30分",
14511     *                 "textbook_url": "/textbook/page-detail/1/1",
14512     *                 "categoryNameLabel": "Category Name",
14513     *                 "subCategoryNameLabel": "Subcategory Name",
14514     *                 "textbookNameLabel": "Textbook Name",
14515     *                 "rate": 5,
14516     *                 "chat_logs_url": "/chat-history/1/1",
14517     *                 "has_message_logs": true,
14518     *                 "message_logs_url": "/lesson-message/detail/1",
14519     *                 "audio_count_log": 1,
14520     *                 "textbook_image": "http://example.com/image.jpg"
14521     *             },
14522     *             ...
14523     *         ]
14524     *     }
14525     *
14526     * @apiError {Boolean} res Indicates whether the request was successful.
14527     *
14528     * @apiErrorExample {json} Error-Response:
14529     *     {
14530     *         "res": false
14531     *     }
14532     * 
14533     * @apiSampleRequest off
14534     */
14535    public function getCounselorLessonHistory() {
14536        $this->autoRender = false;
14537        $this->layout = false;
14538        $response = json_encode(array('res' => false)); // default
14539        
14540        if($this->request->is('post')) {
14541            $post = $this->request->data;
14542            if (!isset($post['teacherId']) && $post['teacherId']) {
14543                return json_encode($response);
14544            }
14545            $teacherId = $post['teacherId'] ?? null;
14546
14547            //NC-7984 start
14548            $lesson_history_data = $this->LessonSchedule->latestCounselorLessonHistory($this->Auth->user('id'), 10);
14549            if(!empty($lesson_history_data) && $lesson_history_data) {
14550                $textbookNamesCachedArr = $lesson_history_data['textbookNamesCachedArr'];
14551
14552                foreach ($lesson_history_data['lessonHistory'] as $key => $value) {
14553                    $dteStart = new DateTime($value['LessonOnairsLog']['start_time']);
14554                    $dteEnd   = new DateTime($value['LessonOnairsLog']['end_time']);
14555
14556                    $logDetail = new LessonOnairsLogTable($value['LessonOnairsLog']);
14557
14558                    $lessonTime = $dteStart->diff($dteEnd);
14559                    $lessonHistoryTime = $lessonTime->format("%I");
14560
14561                    $textbookOrder = isset($textbookNamesCachedArr[$value['TextbookConnect']['id']]['order']) ? $textbookNamesCachedArr[$value['TextbookConnect']['id']]['order'] : '';
14562
14563                    $categoryName = $value['TextbookCategory']['name'];
14564                    $subcategoryName = $value['TextbookSubategory']['name'];
14565                    $textbookName = $value['Textbook']['name'];
14566                    $textbookMainTopicName = isset($value['Textbook']['main_topic_name']) ? $value['Textbook']['main_topic_name'] : '';
14567
14568                    // - if has translated Category name
14569                    if (isset($value['GlobalTextbookCategory']['gl_name']) && $value['GlobalTextbookCategory']['gl_name']) {
14570                        $categoryName = $value['GlobalTextbookCategory']['gl_name'];
14571                    }
14572
14573                    // - if has translated subcategory name
14574                    if (isset($value['GlobalTextbookSubcategory']['gl_name']) && $value['GlobalTextbookSubcategory']['gl_name']) {
14575                        $subcategoryName = $value['GlobalTextbookSubcategory']['gl_name'];
14576                    }
14577
14578                    // - if has translated textbook name
14579                    if (isset($value['GlobalTextbook']['gl_name']) && $value['GlobalTextbook']['gl_name']) {
14580                        $textbookName = $value['GlobalTextbook']['gl_name'];
14581                    }
14582
14583                    // - set textbook name
14584                    $categoryNameLabel = $categoryName;
14585                    $subCategoryNameLabel = $subcategoryName;
14586                    $subCategoryNameLabel = $textbookMainTopicName ? $textbookMainTopicName : $subcategoryName;
14587                    $textbookNameLabel = $textbookOrder . $textbookName;
14588                    $textbook_url = "/textbook/page-detail/{$value['TextbookCategory']['type_id']}/{$value['LessonOnairsLog']['connect_id']}";
14589
14590                    $has_message_logs = !empty($value['LessonOnairsLog']['lesson_memo']) && $value['LessonOnairsLog']['lesson_memo_disp_flg'] == 1 && $value['LessonOnairsLog']['display_message'] == 1;
14591                    $message_logs_url = "/lesson-message/detail/{$value['LessonOnairsLog']['id']}";
14592                    $teacher_id = $value['LessonOnairsLog']['teacher_id'];
14593                    $chat_logs_url = "/chat-history/{$teacher_id}/{$value['LessonOnairsLog']['chat_hash']}";
14594
14595                    $lesson_history_data['lessonHistory'][$key]['lesson_number'] = $value['LessonTrackLogs']['lesson_number'];
14596                    $lesson_history_data['lessonHistory'][$key]['chatStartJPDate'] = $logDetail->chatStartJPDate($this->timeDiffSecond);
14597                    $lesson_history_data['lessonHistory'][$key]['chatStartTime'] = $logDetail->chatStartTime($this->timeDiffSecond);
14598                    $lesson_history_data['lessonHistory'][$key]['lessonHistoryTime'] = $lessonHistoryTime. __('分');
14599                    $lesson_history_data['lessonHistory'][$key]['textbook_url'] = $textbook_url;
14600                    $lesson_history_data['lessonHistory'][$key]['categoryNameLabel'] = $categoryNameLabel;
14601                    $lesson_history_data['lessonHistory'][$key]['subCategoryNameLabel'] = $subCategoryNameLabel;
14602                    $lesson_history_data['lessonHistory'][$key]['textbookNameLabel'] = $textbookNameLabel;
14603                    $lesson_history_data['lessonHistory'][$key]['rate'] = $value['usersClassEvaluations']['rate'];
14604                    $lesson_history_data['lessonHistory'][$key]['chat_logs_url'] = $chat_logs_url;
14605                    $lesson_history_data['lessonHistory'][$key]['has_message_logs'] = $has_message_logs;
14606                    $lesson_history_data['lessonHistory'][$key]['message_logs_url'] = $message_logs_url;
14607                    $lesson_history_data['lessonHistory'][$key]['audio_count_log'] = $value['LessonOnairsLog']['temp_flg1'];
14608                    $lesson_history_data['lessonHistory'][$key]['textbook_image'] = $value['TextbookCategory']['image_big_url'];
14609                }
14610                
14611                $response = json_encode(array(
14612                    'res' => true, 
14613                    'lessonHistory' => $lesson_history_data['lessonHistory']
14614                ));
14615            }
14616        }
14617        return $response;
14618    }
14619
14620    /**
14621     * @api {get} /user/waiting/speakingTestAttendance speakingTestAttendance()
14622     * @apiName speakingTestAttendance
14623     * @apiGroup Waiting
14624     * @apiDescription Retrieves the attendance status for the speaking test and counseling sessions for the authenticated user in Native Camp. It returns the URLs, CSS classes, and text for the speaking test and counseling status.
14625     * 
14626     * @apiSuccess {String} speakingTestDailyFlgUrl The URL for the daily speaking test.
14627     * @apiSuccess {String} speakingTestBusinessFlgUrl The URL for the business speaking test.
14628     * @apiSuccess {String} speakingTestDailyFlgClass The CSS class for the daily speaking test status.
14629     * @apiSuccess {String} speakingTestBusinessFlgClass The CSS class for the business speaking test status.
14630     * @apiSuccess {String} counselingFlgClass The CSS class for the counseling status.
14631     * @apiSuccess {String} speakingTestDailyFlgTxt The text for the daily speaking test status.
14632     * @apiSuccess {String} speakingTestBusinessFlgTxt The text for the business speaking test status.
14633     * @apiSuccess {String} counselingFlgTxt The text for the counseling status.
14634     *
14635     * @apiSuccessExample {json} Success-Response:
14636     *     {
14637     *         "speakingTestDailyFlgUrl": "http://example.com/en/speaking_test/daily_start",
14638     *         "speakingTestBusinessFlgUrl": "http://example.com/en/speaking_test/business_start",
14639     *         "speakingTestDailyFlgClass": "",
14640     *         "speakingTestBusinessFlgClass": "",
14641     *         "counselingFlgClass": "",
14642     *         "speakingTestDailyFlgTxt": "未受験",
14643     *         "speakingTestBusinessFlgTxt": "未受験",
14644     *         "counselingFlgTxt": "未受講"
14645     *     }
14646     *
14647     * @apiError {String} error Message indicating the error.
14648     *
14649     * @apiErrorExample {json} Error-Response:
14650     *     {
14651     *         "error": "Invalid request."
14652     *     }
14653     * 
14654     * @apiSampleRequest off
14655     */
14656    public function speakingTestAttendance(){
14657        $this->autoRender = false;
14658        $this->layout = false;
14659
14660        $speakingTestDailyFlgUrl         = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/daily_start";
14661        $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir. "/speaking_test/business_start";
14662        $speakingTestDailyFlgClass         = '';
14663        $speakingTestBusinessFlgClass     = '';
14664        $counselingFlgClass             = '';
14665        $speakingTestDailyFlgTxt         = __d('waiting', '未受験');
14666        $speakingTestBusinessFlgTxt     = __d('waiting', '未受験');
14667        $counselingFlgTxt                 = __d('waiting', '未受講');
14668
14669        $monthlySpeakingTestStatus = array();
14670        if ( $this->request->is('ajax') && !empty($this->sharedUserData['User']['id']) ) {
14671            $monthlySpeakingTestStatus = UserTable::monthlySpeakingTrainingStatus(array(
14672                'user_id' => $this->sharedUserData['User']['id'],
14673                'time_diff' => $this->timeDiffSecond
14674            ));
14675            //-- Speaking training daily
14676            if (!empty($monthlySpeakingTestStatus['speaking_test_daily_english_flg'])) {
14677                $speakingTestDailyFlgClass         = 'done';
14678                $speakingTestDailyFlgUrl         = myTools::getUrl().'/'.$this->localizeDir. "/speaking_test/daily_start?result=true";
14679                $speakingTestDailyFlgTxt = __d('waiting', '受験済み');
14680            }
14681            //-- Speaking training business
14682            if (!empty($monthlySpeakingTestStatus['speaking_test_business_english_flg'])) {
14683                $speakingTestBusinessFlgClass     = 'done';
14684                $speakingTestBusinessFlgUrl     = myTools::getUrl() .'/'.$this->localizeDir."/speaking_test/business_start?result=true";
14685                $speakingTestBusinessFlgTxt = __d('waiting', '受験済み');
14686            }
14687            //-- Counseling
14688            if (!empty($monthlySpeakingTestStatus['counseling_lesson_flg'])) {
14689                $counselingFlgClass = 'done';
14690                $counselingFlgTxt = __d('waiting', '受講済み');
14691            }
14692
14693            $monthlySpeakingTestStatus = array(
14694                'speakingTestDailyFlgUrl'         => $speakingTestDailyFlgUrl,
14695                'speakingTestBusinessFlgUrl'     => $speakingTestBusinessFlgUrl,
14696                'speakingTestDailyFlgClass'     => $speakingTestDailyFlgClass,
14697                'speakingTestBusinessFlgClass'     => $speakingTestBusinessFlgClass,
14698                'counselingFlgClass'             => $counselingFlgClass,
14699                'speakingTestDailyFlgTxt'         => $speakingTestDailyFlgTxt,
14700                'speakingTestBusinessFlgTxt'     => $speakingTestBusinessFlgTxt,
14701                'counselingFlgTxt'                 => $counselingFlgTxt
14702            );
14703        }
14704        return json_encode($monthlySpeakingTestStatus);
14705    }
14706
14707    /**
14708     * @api {get} /user/waiting/getRegion getRegion()
14709     * @apiName getRegion
14710     * @apiGroup Waiting
14711     * @apiDescription Retrieves the list of countries and their regions based on the user's language in Native Camp. It returns the country and region details.
14712     *
14713     * @apiSuccess {Boolean} success Indicates whether the request was successful.
14714     * @apiSuccess {Array} regionDetails The list of countries and their regions.
14715     * @apiSuccess {Object} regionDetails.country The details of a country.
14716     * @apiSuccess {String} regionDetails.country.country_name The name of the country.
14717     * @apiSuccess {Array} regionDetails.country.regions The list of regions in the country.
14718     * @apiSuccess {Object} regionDetails.country.regions.region The details of a region.
14719     * @apiSuccess {String} regionDetails.country.regions.region.id The ID of the region.
14720     * @apiSuccess {String} regionDetails.country.regions.region.region_name The name of the region.
14721     *
14722     * @apiSuccessExample {json} Success-Response:
14723     *     {
14724     *         "success": true,
14725     *         "regionDetails": [
14726     *             {
14727     *                 "country_name": "Japan",
14728     *                 "regions": [
14729     *                     {
14730     *                         "id": "1",
14731     *                         "region_name": "Kanto"
14732     *                     },
14733     *                     ...
14734     *                 ]
14735     *             },
14736     *             ...
14737     *         ]
14738     *     }
14739     *
14740     * @apiError {Boolean} success Indicates whether the request was successful.
14741     * @apiError {String} message The error message.
14742     *
14743     * @apiErrorExample {json} Error-Response:
14744     *     {
14745     *         "success": false,
14746     *         "message": "Failed to retrieve region details."
14747     *     }
14748     * 
14749     * @apiSampleRequest off
14750     */
14751    public function getRegion() {
14752        $this->autoRender = false;
14753
14754        $userLang = $this->localizeDir ? $this->localizeDir : Configure::read('original_language_default');
14755        $languageId = Configure::read('english_language_id'); // set default
14756        $languageIds = $this->CountryCode->getLanguageList(['field'=>'iso_639_1']);
14757
14758        foreach($languageIds as $key => $language) {
14759            if (strtolower($language) == strtolower($userLang)) {
14760                $languageId = $key;
14761                break;
14762            }
14763        }
14764    
14765        $countryRegions = $this->CountryRegion->getCountryResidence([], $languageId, true);
14766        $countryRegionData = array();
14767        
14768        foreach ($countryRegions as $key => $countryRegion) {
14769            $countryRegionData[$countryRegion['CountryCode']['id']]['country_name'] = !empty($countryRegion['GlobalCountryCode']['gl_name']) ? $countryRegion['GlobalCountryCode']['gl_name'] : $countryRegion['CountryCode']['country_name'];
14770            $countryRegionData[$countryRegion['CountryCode']['id']]['regions'][] = [
14771                'id' => $countryRegion['CountryRegion']['id'],
14772                'region_name' => !empty($countryRegion['GlobalCountryRegion']['gl_name']) ? $countryRegion['GlobalCountryRegion']['gl_name'] : $countryRegion['CountryRegion']['region_name']
14773            ];
14774        }
14775
14776        $response = [
14777            'success' => true,
14778            'regionDetails' => array_values($countryRegionData)
14779        ];
14780
14781        return json_encode($response);
14782    }
14783
14784
14785    //get the country and region/city if display flag is on and delete flag is 0 ; 0 = not deleted
14786    function getResidenceData($getCRData) {
14787        $residenceData = [
14788            'countryName' => '',
14789            'countryFlag' => 'other',
14790            'regionName' => ''
14791        ];
14792        if ((empty($getCRData['CountryCode']['country_name']) && empty($getCRData['CountryRegion']['region_name']))) {
14793            return $residenceData;
14794        }
14795        if ($getCRData['CountryCode']['display_flag'] != 1) {
14796            return $residenceData;
14797        }
14798        if (empty($getCRData['TeacherDetail']['country_id'])) {
14799            return $residenceData;
14800        }
14801        if ($getCRData['CountryRegion']['delete_flag'] == 1) {
14802            return $residenceData;
14803        }
14804    
14805        $residenceData['countryName'] = isset($getCRData['GlobalCountryCode']['gl_name']) ? $getCRData['GlobalCountryCode']['gl_name'] : $getCRData['CountryCode']['country_name'];
14806        $getCountryCode = $this->CountryCode->getCountryFromId($getCRData['TeacherDetail']['country_id']);
14807        if ($getCountryCode) {
14808            $countryCodeLower = strtolower($getCountryCode);
14809            $explodeCountryCode = explode(' ', $countryCodeLower);
14810            $residenceData['countryFlag'] = implode('_', $explodeCountryCode);
14811        }
14812    
14813        if (isset($getCRData['GlobalCountryRegion']['gl_name'])) {
14814            $residenceData['regionName'] = $getCRData['GlobalCountryRegion']['gl_name'];
14815        } elseif (isset($getCRData['CountryRegion']['region_name'])) {
14816            $residenceData['regionName'] = $getCRData['CountryRegion']['region_name'];
14817        }
14818
14819        return $residenceData;
14820    }
14821
14822
14823    /**
14824     * @api {post} /user/waiting/countTeacherReservedLessons countTeacherReservedLessons()
14825     * @apiName countTeacherReservedLessons
14826     * @apiGroup Waiting
14827     * @apiDescription Counts the number of reserved lessons for a specific teacher in Native Camp. It checks if the request is an AJAX request and returns the reservation count.
14828     *
14829     * @apiBody {String} teacher_id The ID of the teacher.
14830     * 
14831     * @apiSuccess {Number} reservation_count The number of reserved lessons for the teacher.
14832     *
14833     * @apiSuccessExample {json} Success-Response:
14834     *     {
14835     *         "reservation_count": 5
14836     *     }
14837     *
14838     * @apiError {String} error Message indicating the error.
14839     *
14840     * @apiErrorExample {json} Error-Response:
14841     *     {
14842     *         "error": "Invalid request data."
14843     *     }
14844     * 
14845     * @apiSampleRequest off
14846     */
14847    public function countTeacherReservedLessons(){
14848        $this->autoRender = false;
14849        $this->layout = false;
14850        $reserveCount = array('reservation_count' => 0);
14851
14852        if ( $this->request->is('ajax') && !empty($this->request->data['teacher_id']) ) {
14853            $teacherId = $this->request->data['teacher_id'];
14854            $reserveCount['reservation_count'] = $this->LessonSchedule->countTeacherReservedLessons(array('teacherId' => $teacherId));
14855        }
14856        return json_encode($reserveCount);
14857    }
14858
14859    /**
14860     * Get Live coupon result for viewers
14861     * @param chathash
14862     * @param users_api_token
14863     * @return json
14864     */
14865    public function getLiveCouponResult()
14866    {
14867        $this->autoRender = false;
14868        $this->layout = false;
14869
14870        $users_api_token = $this->request->data['users_api_token'];
14871        $chat_hash = $this->request->data['chat_hash'];
14872        // open tunnel
14873        myTools::initializeApiTunnel(array('LessonDataController'));
14874
14875        // initialize controller
14876        $lcr = new LessonDataController();
14877
14878        // set data
14879        $lcr->params = [
14880            'nc_terminal_type' => 1,
14881            'chat_hash' => $chat_hash,
14882            'users_api_token' => $users_api_token
14883        ];
14884
14885        // process payment
14886        $response = json_decode($lcr->live_coupon_result(), true);
14887        return json_encode($response);    }
14888
14889    public function checkLessonStartButtonNormal() {
14890        $this->autoRender = false;
14891        $this->layout = false;
14892        $user = $this->sharedUserData;
14893        $data = $this->request->data;
14894        $response = [];
14895        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
14896        $env = Configure::read('ENVIRONMENT');
14897
14898        if(empty($data['teacherId'])) {
14899            $response['error'] = 'Invalid parameters!';
14900            return json_encode($response);
14901        }
14902
14903        $studentId = (int) $data['studentId'];
14904        $teacherId = (int) $data['teacherId'];
14905        $counselingFlg = $data['counselingFlg'] ?? 0;
14906        myTools::initializeApiTunnel(array('TeachersDetailController'));
14907        $TeachersDetailController = new TeachersDetailController();
14908        $TeachersDetailController->params = [
14909            'nc_terminal_type' => 1, // pc
14910            'users_api_token' => $user['User']['api_token'],
14911            'teachers_id' => (int) $data['teacherId'],
14912            'la' => $data['la']
14913        ];    
14914        $api = json_decode($TeachersDetailController->detail(), true);        
14915
14916        if (json_last_error() !== JSON_ERROR_NONE) {
14917            $response['error'] = 'Failed to decode API response.';
14918            return json_encode($response);
14919        }
14920
14921        $isGuestViewer = empty($studentId) ? 1 : 0;
14922        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
14923        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
14924        $lessonStartBtnText10minsRemaining = __d('waiting','レッスン終了まで あと%s分');
14925        $lessonOrangeButtonRemaining = false;
14926        $canLessonParam = array(
14927            'homeFlag' => isset($api['CommonTeacherStatus']['Teacher']['home_flg']) ? $api['CommonTeacherStatus']['Teacher']['home_flg'] : null,
14928            'isGuestViwer' => $isGuestViewer
14929        );    
14930        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);
14931        $liveDefault = (object)[
14932            'max_viewer' => Configure::read('max_live_lesson_viewer'),
14933            'lesson_flg' => 0,
14934            'lesson_joined' => 0,
14935            'lesson_started' => 0,
14936            'lesson_finish' => 0
14937        ];
14938        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;        
14939        
14940        $loginDialog = [
14941            'headerMessage' => __d('login', 'ログインが必要です'),
14942            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
14943            'loginBtn' =>  __d('login', 'ログインはこちら'),
14944            'registerBtn' => __d('login', '新規会員登録はこちら')
14945        ];
14946        $json = [
14947            'lessonStartBtnText' => $lessonStartBtnText,
14948            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
14949            'lessonStartBtnText10minsRemaining' => $lessonStartBtnText10minsRemaining,
14950            'isGuestViewer' => (bool) $isGuestViewer,
14951            'loginDialog' => $loginDialog,
14952            'fullBaseUrl' => $this->baseUrl,
14953            'canLesson' => $canLesson
14954        ];
14955        $remainingLessonTime = 0;
14956        
14957        $canMidwayLesson = false;
14958        $isViewer = 0;
14959        $onair = $api['LessonOnair'];
14960        $hasRemainingLife = false;
14961        $unsupportedBrowser = false;
14962        $browser = $this->request->header('User-Agent');
14963
14964        if (preg_match('/(Edg|Edge)/i',$browser) ) {
14965            $unsupportedBrowser = false;
14966        } elseif (preg_match('/(OPR)/i',$browser)) {
14967            $unsupportedBrowser = true;
14968        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
14969            $unsupportedBrowser = false;
14970        } else {
14971            $unsupportedBrowser = true;
14972        }
14973
14974        $currentMin = date('i');
14975
14976        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
14977            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
14978        } else {
14979            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
14980        }
14981
14982        if(
14983            $liveData->lesson_flg && 
14984            (
14985                (
14986                    !is_null($onair['user_id']) &&
14987                    $onair['user_id'] == $studentId
14988                )
14989                ||
14990                (
14991                    is_null($onair['user_id']) &&
14992                    $reservedId &&
14993                    $reservedId != $studentId
14994                )
14995            )
14996        ) {
14997            $isViewer = 1;
14998        }
14999
15000        if(!$isGuestViewer) {        
15001            if(!empty($api['error'])) {
15002                $json['api_error'] = $api['error'];
15003                return json_encode($json);
15004            }
15005
15006            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15007            $stateButton = $api['teacher']['state_button'];
15008            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15009            $_teacherStatus = $api['TeacherStatus'];
15010            $reservedLessonData = $api['reservedLessonData'];
15011            $isReserved = $api['isReserved'];
15012            $teacher = $api['CommonTeacherStatus']['Teacher'];
15013            $remainingLessonTime = $api['remainingLessonTime'];
15014            $checkBadge = $api['checkBadge'];
15015            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15016            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15017            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15018            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15019            $userNotEligible = false;
15020            $lessonType = false;
15021            $lessonOnOther = false;
15022            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
15023            $userDuplicateLesson = false;
15024            $isReservedCanSuddenLesson = false;
15025            $isReservedCanLessonViewing = false;
15026            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
15027            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
15028            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
15029            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
15030            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
15031            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
15032            $hasLessonBeforeActualTime = false;
15033            $teacherStatusColor = '';
15034            $ownReservationFlg = 0;
15035            $liveStatus = 0;
15036            $isBusy = false;
15037            $use7DaysTrialModal = false;
15038            $redirectPlanUrl = '';
15039            $teacherLeaveNotice = '';
15040            $showNativeSpeakerWarning = false;
15041            $baseUrl = myTools::getUrl($this->localizeDir);
15042
15043            // get reservation
15044            $nextReservation = LessonScheduleTable::getReservation(array(
15045                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
15046                'LessonSchedule.user_id' => $data['studentId']
15047            ));
15048
15049            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
15050            $queryCondition = array(
15051                'fields' => array(
15052                    'TeacherRankCoin.coins',
15053                    'TeacherRankCoin.reserve_coin_settings_flg',
15054                    'LessonOnair.id',
15055                    'LessonOnair.teacher_id',
15056                    'LessonOnair.user_id',
15057                    'TeacherRankCoin.limited_plan_reservation'
15058                ),
15059                'joins' => array(
15060                    array(
15061                        'type' => 'LEFT',
15062                        'table' => 'teacher_rank_coins',
15063                        'alias' => 'TeacherRankCoin',
15064                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
15065                    )
15066                ),
15067                'conditions' => array(
15068                    array('Teacher.id' => $teacher['id'])
15069                ),
15070                'show' => 'first'
15071            );
15072
15073            $commonTeacherStatusParams = array(
15074                'page_display' => 'listTeacher',
15075                'query_conditions' => $queryCondition
15076            );
15077
15078            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15079            $loStatusParams = array(
15080                'LessonOnair' => $commonTeacher2['LessonOnair'],
15081                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
15082                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
15083                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
15084                'userId' => $studentId
15085            );
15086            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
15087            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
15088            $sapuriCoin = $api['teacher']['sapuri_coin'];
15089
15090            if(empty($reservedLessonData)) {
15091                $this->LessonSchedule->recursive = 0;
15092                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
15093            }
15094
15095            // additional state button check from callLessonAlertandStartButton
15096            if(in_array($stateButton, $stateButtonAddntlCheck)) {
15097                // check if lessonOnair is empty
15098                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
15099                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
15100                    if (!$tmp->id) {
15101                        $api['CommonTeacherStatus']['LessonOnair'] = null;
15102                    }
15103                }
15104                
15105                // check if lessonOnair contains empty values
15106                $oOnair = !empty($teacherStatus1) && empty($onair) 
15107                            ? new TeacherStatusTable($teacherStatus1) 
15108                            : $onair;    
15109
15110                //get next available schedule
15111                $checkNextSchedule = null;
15112                $checkScheduleCurrent = null;
15113                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
15114
15115                if(isset($canLesson['nextReserve'])) {
15116                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
15117                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
15118                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
15119                }
15120
15121                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
15122                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
15123                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
15124
15125                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
15126                if (
15127                    (($canLesson['lessonAvailable']
15128                    && !$checkNextSchedule 
15129                    && $checkScheduleCurrent)
15130                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
15131                    && !($api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1)
15132                    && !$isEmergencyLesson  # ~don't show in emergency page
15133                    && !$this->isStudySapuriTosUser
15134                    && $api['CommonTeacherStatus']['Teacher']['home_flg'] != 1 // not home based teacher
15135                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
15136                ) {
15137                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
15138                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
15139                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
15140                }
15141
15142                // NJ-29831: check if user has reserved lesson for the next 5 min
15143                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherId);
15144                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
15145                $hasLessonBeforeActualTime = false;
15146
15147                if (!empty($scheduleReservationData) && !$onGoingLesson) {
15148                    $hasLessonBeforeActualTime = true;
15149                    $isReserved = true;
15150                }
15151    
15152                //get preset textbook or last viewed
15153                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
15154    
15155                //add additional parameter in fetching preset textbook
15156                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
15157                    $presetParams["lang"] = $this->localizeDir;
15158                }
15159    
15160                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
15161                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
15162                    # for preset
15163                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
15164                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15165    
15166                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
15167                    # use last viewed textbook if no preset data.
15168                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
15169                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
15170                }
15171    
15172                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
15173                $presetParams['is_pc_flg'] = 1;
15174    
15175                # fetch preset
15176                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15177                if(!$preset) {
15178                    unset($presetParams['connect_id']);
15179                    unset($presetParams['last_opened_date']);
15180                    $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
15181                }
15182    
15183                $lessonData = $preset["textbook_info"];
15184                $categoryId = $lessonData["TextbookCategory"]["id"];
15185                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
15186                $textbookId = $lessonData["Textbook"]["id"];
15187                
15188                if( $categoryTypeId == 1 ) { // course
15189                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
15190                } else { // series
15191                    $seriesId = $categoryId;
15192                }
15193
15194                if(empty($checkBadge)) {
15195                    $checkBadge = $this->TeacherBadge->find("first", array(
15196                        "conditions" => array(
15197                            "TeacherBadge.teacher_id" => $teacherId,
15198                            "TeacherBadge.textbook_category_id" => $seriesId
15199                        ),
15200                        "fields" => array("TeacherBadge.id"),
15201                        "recursive" => -1
15202                    ));
15203                }
15204
15205                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
15206
15207                //check if the preset textbook is doesn't have reserve_flg
15208                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
15209                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
15210                $browser =  $this->request->header('User-Agent');
15211                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15212
15213                if ($uOnair != null) {
15214                    $uOOnair = new LessonOnairTable($uOnair);
15215                    //check user duplicate lesson
15216                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
15217                        $userDuplicateLesson = true;
15218                        $lessonType = $uOOnair->lesson_type;
15219                    }
15220                    //check lesson on others
15221                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
15222                        $lessonOnOther = true;
15223                    }
15224                }
15225
15226                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
15227                if (
15228                    $canLessonTextbook &&             # - can lesson with the textbook
15229                    !$textbookForReservationOnly && # - textbook not for reserve only
15230                    !$unsupportedBrowser &&         # - supported browser
15231                    $userDuplicateLesson &&         # - has lesson with other teacher
15232                    $lessonType == Configure::read('lesson.type.reservation') &&
15233                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15234                    !$this->isStudySapuriUser &&    # - not sapuri user
15235                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
15236                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15237                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15238                ) {
15239                    $isReservedCanSuddenLesson = true;
15240                }
15241
15242                // if failed settlement -> paid or corporate individual (standard/premium)
15243                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
15244                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
15245                // if free 
15246                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
15247                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
15248                // if free (trial not yet conducted)
15249                } elseif ($this->userMembershipType == 13) {
15250                    $userNotEligible = 10;
15251                    $use7DaysTrialModal = true;
15252                // if corporate company settlement failed -> standard/premium or
15253                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
15254                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
15255                }
15256
15257                if( $teacherStatusNew == '5' ) {
15258                    $ownReservationFlg = 1;
15259                }
15260
15261                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
15262                $membershipTypeReservationOnly = false;
15263
15264                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
15265                    $membershipTypeReservationOnly = true;
15266                }
15267
15268                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
15269                $membershipTypeBlueBtn = false;
15270
15271                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
15272                    $teacherStatusColor = 'wait';
15273                    $membershipTypeBlueBtn = true;
15274                }
15275
15276                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
15277
15278                if(!$isGuestViewer && $liveLessonFlg) {
15279                    $reservedLessonData = $api['reservedLessonData'];
15280
15281                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
15282                        $liveStatus = 0;
15283                    } else {
15284                        //- if lesson started
15285                        if (
15286                            !is_null($api['LessonOnair']['connect_id']) &&
15287                            !is_null($api['LessonOnair']['user_id'])
15288                        ) {
15289                            if ($api['LessonOnair']['user_id'] == $studentId) {
15290                                $liveStatus = 4;
15291                            } else {
15292                                //- check live status
15293                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
15294                                    'user_id' => $studentId,
15295                                    'chat_hash' => $api['LessonOnair']['chat_hash']
15296                                ]);
15297
15298                                //-- override status to watch
15299                                if ($liveStatus == 1) {
15300                                    $liveStatus = 2; //view live
15301                                }
15302                            }
15303                        } else {
15304                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
15305                                'teacher_id' => $teacherId
15306                            ]);
15307
15308                            //-has reservation
15309                            if ($waitingReservationLive) {
15310                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
15311                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
15312                                } else {
15313                                    $liveStatus = 1; //live will start
15314                                }
15315                            }
15316                        }
15317                    }
15318                }
15319
15320                if(!$this->isStudySapuriTosUser) {
15321                    $teacherStudentConnection = $api['teacherStudentConnection'];        
15322                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
15323                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
15324                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
15325                            'teacher_id' => $teacherId,
15326                            'teacherStudentData' => $teacherStudentData,
15327                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
15328                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
15329                            'nickname' => $user['User']['nickname'],
15330                            'admin_flg' => $userAdminFlag,
15331                            'isReserved' => $isReserved,
15332                            'type' => 1
15333                        ));
15334                    }
15335                }
15336
15337                // check if busy
15338                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
15339                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
15340                        $isBusy = true;
15341                    }
15342                }
15343
15344                if(!$isGuestViewer && !isset($remainingLessonTime) || $remainingLessonTime <= 0 || $remainingLessonTime >= 660) {
15345                    $isBusy = true;
15346                }
15347
15348                // NC-5409 : Corporate Limited Plan
15349                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
15350
15351                    // check if legible
15352                    if (
15353                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
15354                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15355                            $userDuplicateLesson || 
15356                            $unsupportedBrowser ||
15357                            $lessonOnOther
15358                        ) &&
15359                        $studentId
15360                    ) {
15361                        $userNotEligible = 1;
15362                    }
15363
15364                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
15365
15366                    $corpLightCondition1 = (
15367                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
15368                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
15369                        $userDuplicateLesson ||
15370                        $unsupportedBrowser ||
15371                        $lessonOnOther
15372                    );
15373                    // check if legible
15374                    if ( $corpLightCondition1 && $studentId) {
15375                        $userNotEligible = 2;
15376                    }
15377                } elseif (
15378                    (
15379                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
15380                        $commonTeacher2['Teacher']['native_speaker_flg']
15381                    ) &&
15382                    (
15383                        $user['User']['native_option'] == null ||
15384                        $user['User']['native_option'] == 0
15385                    ) &&
15386                    !$isReserved &&
15387                    !$tmp->live_lesson_flg &&
15388                    !$this->isStudySapuriTosUser
15389                ) {
15390                    $userNotEligible = 3;
15391                    $showNativeSpeakerWarning = true;
15392                } elseif ( // NJ-48797
15393                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
15394                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
15395                    !$isReserved &&
15396                    !$tmp->live_lesson_flg &&
15397                    !$this->isStudySapuriTosUser
15398                ) {
15399                    $showNativeSpeakerWarning = true;
15400                    $userNotEligible = 4;
15401                } else {
15402                    // check if legible
15403                    if ((
15404                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
15405                        $userDuplicateLesson || 
15406                        $unsupportedBrowser || 
15407                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
15408                        $lessonOnOther
15409                    ) && $studentId) {
15410                        $userNotEligible = 5;
15411                    }
15412                }
15413
15414                # ~no sudden lesson for sapuri toS user
15415                if ($this->isStudySapuriTosUser && !$isReserved) {
15416                    $userNotEligible = 6;
15417                }
15418
15419                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
15420
15421                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
15422                    # disable the lesson button for lite plan if it is not reserved lesson
15423                    $userNotEligible = 7;
15424
15425                    # add if reserve is still ongoing 
15426                    if($isReserved) {
15427                        $userNotEligible = false;
15428                    }
15429                }
15430
15431            }            
15432
15433            switch($stateButton) {
15434                case 2: //proceed_to_the_lesson_immediately
15435                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
15436                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
15437                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
15438                    ) {
15439                        $stateButton = 5; //busy
15440                    }
15441                    break;
15442                case 3: // go to reserved lesson
15443                case 32: // dummy lesson
15444                    $teacherStatusColor = 'lesson';
15445                case 5: //busy
15446                    if( $teacherStatusColor == 'offline' && $membershipTypeReservationOnly ) {
15447                        $stateButton = 6;
15448                    }
15449                    $teacherStatusColor = 'lesson';
15450
15451                    break;
15452                default:
15453            }
15454
15455            $studentRemainingSecondsDelay = 0;
15456            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
15457
15458            $showTakeBusinessTestModal = false;
15459            if (isset($user['User']['corporate_id'])) {
15460                $showTakeBusinessTestModal = false;
15461                $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
15462                $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
15463                $corporateUserDate = time();
15464                $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
15465
15466                if (
15467                    ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
15468                    !$isReserved &&
15469                    (
15470                        $corporateUserDate >= $twentyPlusDayOfTheMonth ||
15471                        (
15472                            $userAdminFlag == 1 ||
15473                            (
15474                                isset($user["User"]["nickname"]) &&
15475                                strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
15476                            )
15477                        )
15478                    )
15479                ) {
15480                    $showTakeBusinessTestModal = true;
15481                }
15482            }
15483
15484            // show orange button
15485            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($studentId, $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
15486
15487            if (
15488                $canLessonTextbook &&             # - can lesson with the textbook
15489                !$textbookForReservationOnly && # - textbook not for reserve only
15490                !$unsupportedBrowser &&         # - supported browser
15491                $userDuplicateLesson &&         # - has lesson with other teacher
15492                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
15493                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
15494                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
15495            ) {
15496                $canMidwayLesson = true;
15497            }
15498        } else {
15499
15500        } //end $isGuestViewer
15501
15502        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
15503        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
15504        $showLoader = $isGuestViewer ? true : false;    
15505        $suddenLessonFlg = false;
15506        $canDoLive = UserTable::canJoinLiveViewing($user['User']);        
15507
15508        if (
15509            $isReserved && 
15510            (
15511                $this->isStudySapuriUser || 
15512                $this->isStudySapuriTosUser || 
15513                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
15514            )
15515        ) {
15516            $canDoLive = false;
15517        }
15518    
15519        if(
15520            !$isViewer && 
15521            !$isEmergencyLesson && 
15522            !$isReservedCanSuddenLesson & 
15523            !$canMidwayLesson &&
15524            !$isReserved
15525        ) {
15526            if($teacherStatusColor == 'wait') {
15527                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
15528                    $isBusy = true;
15529                }
15530    
15531                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
15532                    $suddenLessonFlg = true;
15533                }
15534            }
15535    
15536            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
15537                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
15538                    
15539                    if($membershipTypeBlueBtn) {
15540                        $suddenLessonFlg = true;
15541                        $teacherStatusColor = 'wait';
15542                    }
15543                }
15544            }
15545        }
15546
15547        // set localize url
15548        if (
15549            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
15550            $get['la'] != Configure::read('default.user_language')
15551        ) {
15552            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
15553        } else {
15554            $localizeUrl = myTools::getUrl();
15555        }
15556
15557        $displayFamilyAlert = false;
15558        if (
15559            isset($this->sharedUserData['User']['parent_id']) &&
15560            !is_null($this->sharedUserData['User']['parent_id'])
15561        ) {
15562            $parent = $this->User->find('first', array(
15563                'fields' => array(
15564                    'User.id',
15565                    'User.hash16',
15566                    'User.charge_flg'
15567                ),
15568                'conditions' => array(
15569                    'User.id' => $this->sharedUserData['User']['parent_id']
15570                ),
15571                'recursive' => -1
15572            ));
15573
15574            if ($parent && $parent['User']['charge_flg'] != 1) {
15575                $displayFamilyAlert = true;
15576            }
15577        }
15578
15579        $device = false;
15580        if (strpos($ua, 'Silk') !== false) {
15581            $device = 'kindle';
15582        } else if (strpos($ua, 'Android') !== false) {
15583            $device = 'andriod';
15584        } else if (strpos($ua, 'iPhone') !== false) {
15585            $device = 'ios';
15586        } else if (strpos($ua, 'iPad') !== false) {
15587            $device = 'ios';
15588        } else if (strpos($ua, 'iPod') !== false) {
15589            $device = 'ios';
15590        } else {
15591            $device = 'pc';
15592        }
15593
15594        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
15595        $button = $buttonStates[$stateButton];
15596        $canEmergencyLesson = false;
15597        $currentMinutes = date("i");
15598        $emergencyBreakTime = ['status' => false];
15599        $currentHour = date("H");
15600        
15601        if ($isEmergencyLesson) {
15602            if ($this->isStudySapuriTosUser) {
15603                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
15604                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
15605                $queryCondition['fields'][] = "(
15606                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
15607                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
15608                    ) as can_emergency_lesson";
15609                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
15610                    as student_no_next_reservation";
15611            }
15612
15613            $commonTeacherStatusParams = array(
15614                'page_display' => 'listTeacher',
15615                'query_conditions' => $queryCondition
15616            );
15617            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
15618            
15619            if (
15620                $this->isStudySapuriTosUser &&
15621                !$isReserved &&
15622                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
15623                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
15624                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
15625                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
15626            ) {
15627                $canEmergencyLesson = true;
15628            }
15629
15630            # ~if emergency lesson break time
15631            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
15632                $canEmergencyLesson = false;
15633                $emergencyBreakTime['status'] = true;
15634                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
15635                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
15636            }
15637        }        
15638
15639
15640        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
15641
15642        // lesson alert
15643        $lessonAlertMsg = [];
15644        $lessonAlertStatus = '';
15645
15646        // if emergency lesson break time
15647        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
15648            $lessonAlertMsg = [
15649                ['text' => __d('waiting','しばらくお待ちください。')],
15650                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
15651                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
15652            ];
15653            $lessonAlertStatus = 'emergency_lesson_break_time';
15654        }
15655
15656        if (
15657            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
15658            !$isReserved &&
15659            !$isAvatar
15660        ) {
15661            $lessonAlertMsg = [
15662                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
15663                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
15664                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
15665            ];
15666            $lessonAlertStatus = 'exceed_daily_limit';
15667        }
15668
15669        $schedStartTime = isset($canLesson['nextReservation']['lesson_time']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReservation']['lesson_time']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15670        $schedEndTime = isset($canLesson['possibleTime']) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['possibleTime']), 'timestamp' => $this->timeDiffSecond, 'format' => 'H:i')) : '';
15671
15672        if(
15673            isset($canLesson['possibleTime']) &&
15674            $canLesson['possibleTime'] !== false &&
15675            (!isset($isAvatar) || $isAvatar == false) &&
15676            $studentId &&
15677            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15678            !$isEmergencyLesson
15679        ) {
15680            $canReserveLessonForReserved = 1;
15681        } else {
15682            $canReserveLessonForReserved = 0;
15683        }
15684
15685        if(
15686            isset($canLesson['possibleTime']) &&
15687            $canLesson['possibleTime'] !== false &&
15688            $isAvatar == false &&
15689            $studentId &&
15690            !(isset($exceedDailyLimit) && $exceedDailyLimit) &&
15691            !$this->isStudySapuriTosUser && !$isEmergencyLesson # ~don't show in emergency page
15692        ) {
15693            $lessonAlertStatus == 'lesson_reservation';
15694            $lessonAlertMsg = ['text' => sprintf(__d('waiting','この講師は、%1$s から予約が入っているため、%2$s までのレッスンとなります。ご了承の上レッスンへお進みください。'), $schedStartTime, $schedEndTime)];
15695        }
15696
15697        // user has reserved class (attempts to have a lesson with another teacher)
15698        if (
15699            $isAvatar == false && 
15700            $reservedLessonData && 
15701            (!$canLesson['lessonAvailable']) && !empty($teacherStatus) && ($teacherStatus->status == 1) && 
15702            (!empty($teacherStatus) && isset($teacherStatus->connect_flg) && $teacherStatus->connect_flg == 1 ) && 
15703            !$isReservedCanSuddenLesson
15704        ) {
15705            $lessonAlertStatus = 'reserved_class';
15706        }
15707
15708        $corporateIndividualUser = false;
15709        $corporateTypes = Configure::read('corporate_type_arr');
15710        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
15711        if (isset($user['User']['corporate_id'])) {
15712            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
15713            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
15714        }
15715
15716        if (
15717            !$this->isStudySapuriUser &&
15718            $lessonType == Configure::read('lesson.type.reservation') &&
15719            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
15720        ) {
15721            $isReservedCanLessonViewing = true;
15722        }
15723
15724        if(!$isGuestViewer) {
15725            $json = array_merge($json, [
15726                'apiStateButton' => $api['teacher']['state_button'],
15727                'button' => $button,
15728                'canDoLive' => $canDoLive,
15729                'canEmergencyLesson' => $canEmergencyLesson,
15730                'canLesson' => $canLesson,
15731                'canLessonTextbook' => $canLessonTextbook,
15732                'canMidwayLesson' => $canMidwayLesson,
15733                'canReserveLessonForReserved' => $canReserveLessonForReserved,
15734                'checkBadge' => $checkBadge,
15735                'corporateIndividualUser' => $corporateIndividualUser,
15736                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
15737                'corporateType' => $corporateType,
15738                'corporateUserFlg' => $corporateUserFlg,
15739                'corpLightCondition' => $corpLightCondition1,
15740                'counselingFlg' => $counselingFlg,
15741                'device' => $device,
15742                'displayFamilyAlert' => $displayFamilyAlert,
15743                'dummyLessonRoom' => $hasLessonBeforeActualTime,
15744                'emergencyBreakTime' => $emergencyBreakTime,
15745                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
15746                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
15747                'hasRemainingLife' => $hasRemainingLife,
15748                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
15749                'isAvatar' => $isAvatar,
15750                'isBusy' => $isBusy,
15751                'isEmergencyLesson' => $isEmergencyLesson,
15752                'isNormalLitePlanUser' => $isNormalLitePlanUser,
15753                'isRedLamp' => $isRedLamp,
15754                'isReserved' => $isReserved,
15755                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
15756                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
15757                'isStudySapuriTosUser' => $this->isStudySapuriUser,
15758                'isViewer' => $isViewer,
15759                'lessonAlertMsg' => $lessonAlertMsg,
15760                'lessonAlertStatus' => $lessonAlertStatus,
15761                'lessonOnAir' => $teacherStatusOnAir,
15762                'lessonOnOther' => $lessonOnOther,
15763                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
15764                'lessonType' => $lessonType,
15765                'liveData' => $liveData,
15766                'liveLessonFlg' => $liveLessonFlg ?? null,
15767                'liveLessonText' => $liveLessonText,
15768                'liveStatus' => $liveStatus,
15769                'localizeUrl' => $localizeUrl,
15770                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
15771                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
15772                'onair' => $onair,
15773                'uOnair' => $uOnair,
15774                'onGoingLesson' => $onGoingLesson,
15775                'ownReservationFlg' => $ownReservationFlg,
15776                'paymentPlanId' => $user['User']['payment_plan_id'],
15777                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
15778                'redirectPlanUrl' => $redirectPlanUrl,
15779                'remainingLessonTime' => (int) $remainingLessonTime,
15780                'reservedLessonData' => $reservedLessonData,
15781                'sapuriCoin' => $sapuriCoin,
15782                'scheduleReservationData' => $scheduleReservationData,
15783                'schedEndTime' => $schedEndTime,
15784                'schedStartTime' => $schedStartTime,
15785                'showLoader' => $showLoader,
15786                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
15787                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
15788                'stateButton' => $stateButton,
15789                'studentId' => $studentId,
15790                'suddenLessonFlg' => $suddenLessonFlg,
15791                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
15792                'teacherLeaveNotice' => $teacherLeaveNotice,
15793                'teacherStatus' => $teacherStatus,
15794                'teacherStatusApi' => $_teacherStatus,
15795                'teacherStatusColor' => $teacherStatusColor,
15796                'textbookForReservationOnly' => (int)$textbookForReservationOnly,
15797                'unverifiedSMS' => $stateButton == 7 ? true : false,
15798                'unsupportedBrowser' => $unsupportedBrowser,
15799                'use7DaysTrialModal' => $use7DaysTrialModal,
15800                'userAdminFlag' => $userAdminFlag,
15801                'userDoubleCheckFlag' => $userDoubleCheckFlag,
15802                'userDuplicateLesson' => $userDuplicateLesson,
15803                'userFailFlag' => $userFailFlag,
15804                'userMembershipType' => $this->userMembershipType,
15805                'userNativeOption' => $user['User']['native_option'],
15806                'userNotEligible' => $userNotEligible
15807            ]);
15808
15809            if($membershipTypeReservationOnly) {
15810                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
15811            }
15812
15813            if(
15814                $remainingLessonTime > 0 && 
15815                $remainingLessonTime < 660 &&
15816                !empty($teacherStatusOnAir['user_id']) && $teacherStatusOnAir['user_id'] != $studentId
15817            ) {
15818                $json['remainingLessonEndTime'] = $oOnair['end_time'];
15819
15820                if($remainingLessonTime <= 60) {
15821                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで もうすぐ');
15822                } else {
15823                    $json['lessonStartBtnText'] = __d('waiting', 'レッスン終了まで あと%s分');
15824                }
15825            }
15826
15827            if($suddenLessonFlg) {
15828                if($use7DaysTrialModal) {
15829                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
15830                } else if (!empty(trim($redirectPlanUrl))) {
15831                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
15832                } else if ($showNativeSpeakerWarning) {
15833                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
15834                } else if ($unsupportedBrowser) {
15835                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
15836                } else if (!$canLessonTextbook) {
15837                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
15838                } else if (!empty($teacherLeaveNotice)) {
15839                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
15840                }
15841
15842                if(!empty($json['suddenLessonStatus'])) {
15843                    $json['validateSuddenLessonFlg'] = false;
15844                } else {
15845                    $json['validateSuddenLessonFlg'] = true;
15846                }
15847            }
15848
15849        } else if ($isGuestViewer || $isViewer) {
15850            $json = array_merge($json, [
15851                'canLesson' => $canLesson,
15852                'isViewer' => $isViewer,
15853            ]);
15854        }
15855
15856        if($env != 'PRODUCTION') {
15857            $json['api'] = $api;
15858            $json['commonTeacher2'] = $commonTeacher2;
15859            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
15860            $json['teacherStudentConnection'] = $api['teacherStudentConnection'];
15861            $json['tmpLessonOnAir'] = $tmp;
15862            $json['nextEmergencySlot'] = $nextEmergencySlot;
15863            $json['nextReserveSlot'] = $nextReserveSlot;
15864        }
15865
15866        return json_encode($json);
15867    }
15868
15869    public function checkLessonStartButtonAvatar() {
15870        $this->autoRender = false;
15871        $this->layout = false;
15872        $user = $this->sharedUserData;
15873        $data = $this->request->data;
15874        $response = [];
15875        $ua = myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT']) ?? '';
15876        $env = Configure::read('ENVIRONMENT');
15877    
15878        if(empty($data['teacherId'])) {
15879            $response['error'] = 'Invalid parameters!';
15880            return json_encode($response);
15881        }
15882    
15883        // if api token is not set
15884        if (empty($user['User']['api_token'])) {
15885            $userApiToken = $this->User->generateAndSaveApiToken($data['studentId']);
15886            $this->Session->write('Auth.User.api_token', $userApiToken);
15887        }
15888    
15889        $studentId = (int) $data['studentId'];
15890        $teacherId = (int) $data['teacherId'];
15891        $counselingFlg = $data['counselingFlg'] ?? 0;
15892        myTools::initializeApiTunnel(array('TeachersDetailController'));
15893        $TeachersDetailController = new TeachersDetailController();
15894        $TeachersDetailController->params = [
15895            'nc_terminal_type' => 1, // pc
15896            'users_api_token' => $user['User']['api_token'],
15897            'teachers_id' => (int) $data['teacherId'],
15898            'la' => $data['la']
15899        ];    
15900        $api = json_decode($TeachersDetailController->detail(), true);
15901
15902        if (json_last_error() !== JSON_ERROR_NONE) {
15903            $response['error'] = 'Failed to decode API response.';
15904            return json_encode($response);
15905        }
15906
15907        $isGuestViewer = empty($studentId) ? 1 : 0;
15908        $lessonStartBtnText = __d('waiting','今すぐレッスンへ進む');
15909        $lessonStartBtnTextBusy = __d('waiting','取り込み中');
15910        $lessonOrangeButtonRemaining = false;
15911        $loginDialog = [
15912            'headerMessage' => __d('login', 'ログインが必要です'),
15913            'message' => __d('login', 'こちらの機能は、ログイン後にご利用いただけます.'),
15914            'loginBtn' =>  __d('login', 'ログインはこちら'),
15915            'registerBtn' => __d('login', '新規会員登録はこちら')
15916        ];
15917        $json = [
15918            'lessonStartBtnText' => $lessonStartBtnText,
15919            'lessonStartBtnTextBusy' => $lessonStartBtnTextBusy,
15920            'isGuestViewer' => (bool) $isGuestViewer,
15921            'loginDialog' => $loginDialog,
15922            'fullBaseUrl' => $this->baseUrl,
15923        ];
15924        $canLessonParam = array(
15925            'homeFlag' => isset($api['teacher']['home_flg']) ? $api['teacher']['home_flg'] : null,
15926            'isGuestViwer' => $isGuestViewer
15927        );
15928        $canMidwayLesson = false;
15929        $canLesson = LessonOnairTable::canLesson($teacherId, $studentId, $canLessonParam);    
15930        $liveDefault = (object)[
15931            'max_viewer' => Configure::read('max_live_lesson_viewer'),
15932            'lesson_flg' => 0,
15933            'lesson_joined' => 0,
15934            'lesson_started' => 0,
15935            'lesson_finish' => 0
15936        ];
15937        $liveData = isset($canLesson['liveLessonDetail']) && !empty($canLesson['liveLessonDetail']) ? $canLesson['liveLessonDetail'] : $liveDefault;
15938        $currentMin = date('i');
15939        $isViewer = 0;
15940        $onair = $api['LessonOnair'];
15941        $hasRemainingLife = false;
15942        $unsupportedBrowser = false;
15943        $browser =  $this->request->header('User-Agent');
15944
15945        if (preg_match('/(Edg|Edge)/i',$browser) ) {
15946            $unsupportedBrowser = false;
15947        } elseif (preg_match('/(OPR)/i',$browser)) {
15948            $unsupportedBrowser = true;
15949        } elseif (preg_match('/(Chrome|Firefox|Safari)/i',$browser)) {
15950            $unsupportedBrowser = false;
15951        } else {
15952            $unsupportedBrowser = true;
15953        }
15954
15955        if (($currentMin >= 25 && $currentMin < 30) || ($currentMin >= 55 && $currentMin <= 59)) {
15956            $reservedId = isset($canLesson['nextReservation']['user_id']) ? $canLesson['nextReservation']['user_id'] : null;
15957        } else {
15958            $reservedId = isset($canLesson['currentReservation']['user_id']) ? $canLesson['currentReservation']['user_id'] : null;
15959        }
15960
15961        if(
15962            $liveData->lesson_flg && 
15963            (
15964                (
15965                    !is_null($onair['user_id']) &&
15966                    $onair['user_id'] == $studentId
15967                )
15968                ||
15969                (
15970                    is_null($onair['user_id']) &&
15971                    $reservedId &&
15972                    $reservedId != $studentId
15973                )
15974            )
15975        ) {
15976            $isViewer = 1;
15977        }
15978
15979        $isGuestViewer = (empty($studentId) && $isViewer) ? 1 : 0;
15980    
15981        if(!$isGuestViewer) {
15982            if(!empty($api['error'])) {
15983                $json['api_error'] = $api['error'];
15984                return json_encode($json);
15985            }
15986    
15987            $buttonStates = array_flip(Configure::read('user_detail_state_button'));
15988            $stateButton = $api['teacher']['state_button'];
15989            $teacherStatusOnAir = $api['LessonOnair'] ?? null;
15990            $_teacherStatus = $api['TeacherStatus'];
15991            $reservedLessonData = $api['reservedLessonData'];
15992            $isReserved = $api['isReserved'];
15993            $teacher = $api['CommonTeacher`Status']['Teacher'];
15994            $checkBadge = $api['checkBadge'];
15995            $teacherStatus = !empty($_teacherStatus) && empty($teacherStatusOnAir) ? $_teacherStatus : $teacherStatusOnAir;
15996            $_paymentPlanID = isset($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : null;
15997            $isNormalLitePlanUser = (in_array($_paymentPlanID, Configure::read('lite_payment_plans') ) ) ? true : false;
15998            $stateButtonAddntlCheck = Configure::read('user_detail_state_button_addntl_check');
15999            $userNotEligible = false;
16000            $lessonType = false;
16001            $lessonOnOther = false;
16002            $lessonStartBtnText = $isNormalLitePlanUser ? __d('waiting','予約専用です') : __d('waiting','今すぐレッスンへ進む');
16003            $userDuplicateLesson = false;
16004            $isReservedCanSuddenLesson = false;
16005            $isReservedCanLessonViewing = false;
16006            $userAdminFlag = isset($user['User']['admin_flg']) ? $user['User']['admin_flg'] : '';
16007            $userFailFlag = isset($user['User']['fail_flg']) ? $user['User']['fail_flg'] : '';
16008            $userDoubleCheckFlag = isset($user['User']['double_check_flg']) ? $user['User']['double_check_flg']: '';
16009            $userCardCompany = isset($user['User']['card_company']) ? $user['User']['card_company']: '';
16010            $corporateUserFlg = isset($user['User']['corporate_id']) ? $user['User']['corporate_id'] : false;
16011            $isEmergencyLesson = (isset($data['emergencyFlg']) && $data['emergencyFlg']) ? true : false;
16012            $hasLessonBeforeActualTime = false;
16013            $teacherStatusColor = '';
16014            $ownReservationFlg = 0;
16015            $liveStatus = 0;
16016            $isBusy = false;
16017            $use7DaysTrialModal = false;
16018            $redirectPlanUrl = '';
16019            $teacherLeaveNotice = '';
16020            $showNativeSpeakerWarning = false;
16021            $baseUrl = myTools::getUrl($this->localizeDir);                
16022            
16023            // get reservation
16024            $nextReservation = LessonScheduleTable::getReservation(array(
16025                'LessonSchedule.teacher_id' => $api['CommonTeacherStatus']['Teacher']['id'],
16026                'LessonSchedule.user_id' => $data['studentId']
16027            ));
16028
16029            $this->Teacher->unbindModel(array('hasOne' => array('LessonOnair')));
16030            $queryCondition = array(
16031                'fields' => array(
16032                        'TeacherRankCoin.coins',
16033                        'TeacherRankCoin.reserve_coin_settings_flg',
16034                        'LessonOnair.id',
16035                        'LessonOnair.teacher_id',
16036                        'LessonOnair.user_id',
16037                        'TeacherRankCoin.limited_plan_reservation'
16038                    ),
16039                'joins' => array(
16040                    array(
16041                        'type' => 'LEFT',
16042                        'table' => 'teacher_rank_coins',
16043                        'alias' => 'TeacherRankCoin',
16044                        'conditions' => array('Teacher.rank_coin_id = TeacherRankCoin.id AND TeacherRankCoin.status')
16045                    )
16046                ),
16047                'conditions' => array(
16048                    array('Teacher.id' => $teacherId)
16049                ),
16050                'show' => 'first'
16051            );
16052
16053            $commonTeacherStatusParams = array(
16054                'page_display' => 'listTeacher',
16055                'query_conditions' => $queryCondition
16056            );
16057
16058            $commonTeacher2 = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16059            $loStatusParams = array(
16060                'LessonOnair' => $commonTeacher2['LessonOnair'],
16061                'Teacher' => $api['CommonTeacherStatus']['Teacher'],
16062                'TeacherStatus' => $api['CommonTeacherStatus']['TeacherStatus'],
16063                'nextReservation' => isset($nextReservation['teacher_id']) ? $nextReservation['teacher_id'] : null,
16064                'userId' => $studentId
16065            );
16066            $teacherStatusNew = LessonOnairTable::teacherStatusColor($loStatusParams);
16067            $teacherParams = array(
16068                    'type' => 'first',
16069                    'args' => array(
16070                        'conditions' => array(
16071                            'id' => $teacherId
16072                        ),
16073                        'recursive' => -1
16074                    )
16075                );
16076            $teacherInfo = $this->Teacher->getTeachers($teacherParams);
16077
16078            if (
16079                ($teacher['avatar_id'] &&
16080                $teacherStatus['status'] == 4)
16081            ) {
16082                $teacherStatusNew = 3;
16083            }
16084
16085            if(empty($reservedLessonData)) {
16086                $this->LessonSchedule->recursive = 0;
16087                $reservedLessonData = $this->LessonSchedule->getReservationLessonNow($studentId);
16088            }
16089
16090            $teacherStatusColor = TeacherTable::teacherStatusCSS($teacherStatusNew);
16091            $sapuriCoin = $api['teacher']['sapuri_coin'];
16092    
16093            // additional state button check from callLessonAlertandStartButton
16094            if(in_array($stateButton, $stateButtonAddntlCheck)) {
16095                // check if lessonOnair is empty
16096                if (isset($api['CommonTeacherStatus']['LessonOnair'])) {
16097                    $tmp = (object) $api['CommonTeacherStatus']['LessonOnair'];
16098                    if (!$tmp->id) {
16099                        $api['CommonTeacherStatus']['LessonOnair'] = null;
16100                    }
16101                }
16102    
16103                // check if lessonOnair contains empty values
16104                $oOnair = !empty($teacherStatus1) && empty($onair) 
16105                            ? new TeacherStatusTable($teacherStatus1)
16106                            : $onair;
16107    
16108                //get next available schedule
16109                $checkNextSchedule = null;
16110                $checkScheduleCurrent = null;
16111                $lesson_time_stamp = floor(time() / (30 * 60)) * (30 * 60);
16112    
16113                if(isset($canLesson['nextReserve'])) {
16114                    $nextSchedule = isset($canLesson['nextReserve']['start']) ? $canLesson['nextReserve']['start'] : null;
16115                    $checkNextSchedule = $nextSchedule ? $this->ShiftWorkOn->checkDataExist($teacherId , $nextSchedule) : null;
16116                    $checkScheduleCurrent = $this->ShiftWorkOn->checkDataExist( $teacherId , date('Y-m-d H:i:s',$lesson_time_stamp));
16117                }
16118    
16119                $checkNextSchedule = !empty($checkNextSchedule) ? $checkNextSchedule : false;
16120                $checkScheduleCurrent = !empty($checkScheduleCurrent) ? $checkScheduleCurrent : false;
16121                $nextSchedule = isset($nextSchedule) ? $nextSchedule : '';
16122    
16123                // add trappings for meal break, and change $canLesson['nextReserve']['start'] to mealbreak slot if has mealbreak
16124                if (
16125                    (($canLesson['lessonAvailable']
16126                    && !$checkNextSchedule 
16127                    && $checkScheduleCurrent)
16128                    || (isset($canLesson['hasMealbreakNext']) && $canLesson['hasMealbreakNext']))
16129                    && !($teacherInfo['Teacher']['avatar_parent_flg'] == 1 || $teacherInfo['Teacher']['avatar_flg'] == 1)
16130                    && !$isEmergencyLesson  # ~don't show in emergency page
16131                    && !$this->isStudySapuriTosUser
16132                    && $teacherInfo['Teacher']['home_flg'] != 1 // not home based teacher
16133                    && isset($exceedDailyLimit) && !empty($exceedDailyLimit) 
16134                ) {
16135                    $teacherLeaveNotice .= __d('waiting','こちらの講師は'). " ";
16136                    $teacherLeaveNotice .= isset($nextSchedule) ? TimezoneTable::computeTimeToUser(array('time' => strtotime($canLesson['nextReserve']['start']), 'timestamp' => $this->timeDiffSecond, 'format' => 'h:i')) : '';
16137                    $teacherLeaveNotice .= " ". __d('waiting','までのレッスンとなりますので<br>ご了承ください。');
16138                }
16139    
16140                // NJ-29831: check if user has reserved lesson for the next 5 min
16141                $scheduleReservationData = $this->LessonSchedule->getScheduledReservationNow($studentId, $teacherInfo['Teacher']['id']);
16142                $onGoingLesson = $this->LessonOnair->hasOngoingLesson($this->Auth->user('id'));
16143                $hasLessonBeforeActualTime = false;
16144    
16145                if (!empty($scheduleReservationData) && !$onGoingLesson) {
16146                    $hasLessonBeforeActualTime = true;
16147                    $isReserved = true;
16148                }
16149    
16150                //get preset textbook or last viewed
16151                $presetParams = array("user_id" => $studentId, 'userValidForSSBEDT' => $this->userValidForSSBEDT());
16152    
16153                //add additional parameter in fetching preset textbook
16154                if (isset($this->localizeDir) && in_array($this->localizeDir, Configure::read("global_textbook_support_languages"))) {
16155                    $presetParams["lang"] = $this->localizeDir;
16156                }
16157    
16158                $preset_data = $this->UsersTextbookInfo->getPreset($presetParams);
16159                if(isset($preset_data['preset_connect_id']) && !empty($preset_data['preset_connect_id'])) {
16160                    # for preset
16161                    $presetParams['connect_id'] = $preset_data['preset_connect_id'];
16162                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16163    
16164                } else if(isset($preset_data['last_viewed_connect_id']) && !empty($preset_data['last_viewed_connect_id'])) {
16165                    # use last viewed textbook if no preset data.
16166                    $presetParams['connect_id'] = $preset_data['last_viewed_connect_id'];
16167                    $presetParams['last_opened_date'] = $preset_data['last_viewed_date'];
16168                }
16169    
16170                // - NJ-3878 : add trapping for pc and app(api) 1 = pc 0 = app
16171                $presetParams['is_pc_flg'] = 1;
16172    
16173                # fetch preset
16174                $preset  =  $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16175                if(!$preset) {
16176                    unset($presetParams['connect_id']);
16177                    unset($presetParams['last_opened_date']);
16178                    $preset = $this->UsersTextbookInfo->getTextbookInfos($presetParams);
16179                }
16180    
16181                $lessonData = $preset["textbook_info"];
16182                $categoryId = $lessonData["TextbookCategory"]["id"];
16183                $categoryTypeId = $lessonData["TextbookCategory"]["type_id"];
16184                $textbookId = $lessonData["Textbook"]["id"];
16185                
16186                if( $categoryTypeId == 1 ) { // course
16187                    $seriesId = $this->Textbook->getTextbookSeriesId(array( 'textbook_id' => $textbookId ));
16188                } else { // series
16189                    $seriesId = $categoryId;
16190                }
16191
16192                if(empty($checkBadge)) {
16193                    $checkBadge = $this->TeacherBadge->find("first", array(
16194                        "conditions" => array(
16195                            "TeacherBadge.teacher_id" => $teacherId,
16196                            "TeacherBadge.textbook_category_id" => $seriesId
16197                        ),
16198                        "fields" => array("TeacherBadge.id"),
16199                        "recursive" => -1
16200                    ));
16201                }
16202    
16203                $canLessonTextbook = $checkBadge || $counselingFlg ? true : false;                
16204    
16205                //check if the preset textbook is doesn't have reserve_flg
16206                $textbookForReservationOnly = isset($preset['reservation_flg']) ? $preset['reservation_flg'] : false;
16207                $uOnair = isset($onGoingLesson['LessonOnair']) ? $onGoingLesson['LessonOnair']: '';
16208                
16209                $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16210    
16211                if ($uOnair != null) {
16212                    $uOOnair = new LessonOnairTable($uOnair);
16213                    //check user duplicate lesson
16214                    if ($uOOnair && $uOOnair->status == 3 && $uOOnair->user_id == $this->Auth->User('id') && $uOOnair->teacher_id != $teacherId) {
16215                        $userDuplicateLesson = true;
16216                        $lessonType = $uOOnair->lesson_type;
16217                    }
16218                    //check lesson on others
16219                    if ($oOnair && $oOnair->status == 3 && $oOnair->teacher_id == $teacherId && $oOnair->user_id != $studentId) {
16220                        $lessonOnOther = true;
16221                    }
16222                }
16223    
16224                # - [NJ-18003] conditions for terminate reserved lesson for sudden lesson
16225                if (
16226                    $canLessonTextbook &&             # - can lesson with the textbook
16227                    !$textbookForReservationOnly && # - textbook not for reserve only
16228                    !$unsupportedBrowser &&         # - supported browser
16229                    $userDuplicateLesson &&         # - has lesson with other teacher
16230                    $lessonType == Configure::read('lesson.type.reservation') &&
16231                    !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16232                    !$this->isStudySapuriUser &&    # - not sapuri user
16233                    ($uOnair && $uOnair['leave_lesson']) && # - already left the reserved lesson
16234                    !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16235                    !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16236                ) {
16237                    $isReservedCanSuddenLesson = true;
16238                }
16239    
16240                // if failed settlement -> paid or corporate individual (standard/premium)
16241                if (in_array($this->userMembershipType, Configure::read('membership_type_credit_retry'))) {
16242                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_retry';
16243                // if free 
16244                } elseif ($this->userMembershipType == Configure::read('membership_type_plan_free')) {
16245                    $redirectPlanUrl = $baseUrl . '/payment/payment_credit_charge';
16246                // if free (trial not yet conducted)
16247                } elseif ($this->userMembershipType == 13) {
16248                    $userNotEligible = 10;
16249                    $use7DaysTrialModal = true;
16250                // if corporate company settlement failed -> standard/premium or
16251                } elseif (in_array($this->userMembershipType, Configure::read('membership_type_corporate_company_failed'))) {
16252                    $redirectPlanUrl = $baseUrl . '/account/contract_information';
16253                }
16254
16255                // NJ-48797
16256                $avatarParentFlg = isset($commonTeacher2['Teacher']['avatar_parent_flg']) && $commonTeacher2['Teacher']['avatar_parent_flg'] == 1;
16257
16258                if (!$avatarParentFlg) {
16259                    $getParentAvatarTeacher = $this->Teacher->find('first', array(
16260                        'fields' => array('Teacher.id', 'Teacher.native_speaker_flg'),
16261                        'conditions' => array(
16262                            'Teacher.id' => $commonTeacher2['Teacher']['avatar_id'],
16263                            'Teacher.avatar_parent_flg' => 1
16264                        ),
16265                        'recursive' => -1
16266                    ));
16267                } else {
16268                    $getParentAvatarTeacher = $commonTeacher2;
16269                }
16270                
16271                $membershipTypeReservationOnlyArr = Configure::read('membership_type_blue_btn_reservation_only');
16272                $membershipTypeReservationOnly = false;
16273    
16274                if(in_array($this->userMembershipType, $membershipTypeReservationOnlyArr)) {
16275                    $membershipTypeReservationOnly = true;
16276                }
16277    
16278                $membershipTypeBlueBtnArr = Configure::read('membership_type_blue_btn');
16279                $membershipTypeBlueBtn = false;
16280    
16281                if(in_array($this->userMembershipType, $membershipTypeBlueBtnArr)) {
16282                    $teacherStatusColor = 'wait';
16283                    $membershipTypeBlueBtn = true;
16284                }
16285    
16286                $liveLessonFlg = isset($commonTeacher2['LessonOnair']['live_lesson_flg']) ? $commonTeacher2['LessonOnair']['live_lesson_flg'] : 0;
16287    
16288                if(!$isGuestViewer && $liveLessonFlg) {
16289                    $reservedLessonData = $api['reservedLessonData'];
16290    
16291                    if ($reservedLessonData && $reservedLessonData['Teacher']['id'] != $teacherId) {
16292                        $liveStatus = 0;
16293                    } else {
16294                        //- if lesson started
16295                        if (
16296                            !is_null($api['LessonOnair']['connect_id']) &&
16297                            !is_null($api['LessonOnair']['user_id'])
16298                        ) {
16299                            if ($api['LessonOnair']['user_id'] == $studentId) {
16300                                $liveStatus = 4;
16301                            } else {
16302                                //- check live status
16303                                $liveStatus = $this->LessonOnairsViewer->onGoingLiveStatus([
16304                                    'user_id' => $studentId,
16305                                    'chat_hash' => $api['LessonOnair']['chat_hash']
16306                                ]);
16307    
16308                                //-- override status to watch
16309                                if ($liveStatus == 1) {
16310                                    $liveStatus = 2; //view live
16311                                }
16312                            }
16313                        } else {
16314                            $waitingReservationLive = $this->LessonSchedule->getWaitingLiveReservation([
16315                                'teacher_id' => $teacherId
16316                            ]);
16317    
16318                            //-has reservation
16319                            if ($waitingReservationLive) {
16320                                if ($waitingReservationLive['LessonSchedule']['user_id'] == $studentId) {
16321                                    $liveStatus = (date('i') >= 0 && date('i') <= 26) || (date('i') >= 30 && date('i') <= 56) ? 4 : 0;
16322                                } else {
16323                                    $liveStatus = 1; //live will start
16324                                }
16325                            }
16326                        }
16327                    }
16328                }
16329    
16330                if(!$this->isStudySapuriTosUser) {
16331                    $teacherStudentConnection = $api['teacherStudentConnection'];        
16332                    $teacherStudentData = isset($teacherStudentConnection['TeacherStudentConnection']) ? $teacherStudentConnection['TeacherStudentConnection'] : array();
16333                    if (isset($teacherStudentData['daily_lesson_minutes']) && $teacherStudentData['daily_lesson_minutes']) {
16334                        $exceedDailyLimit = $this->LessonOnair->lessonStartButton(array(
16335                            'teacher_id' => $teacherId,
16336                            'teacherStudentData' => $teacherStudentData,
16337                            'counseling_flg' => isset($commonTeacher2['Teacher']['counseling_flg']) ? $commonTeacher2['Teacher']['counseling_flg'] : 0,
16338                            'avatar_flg' => isset($commonTeacher2['Teacher']['avatar_flg']) ? $commonTeacher2['Teacher']['avatar_flg'] : 0,
16339                            'nickname' => $user['User']['nickname'],
16340                            'admin_flg' => $userAdminFlag,
16341                            'isReserved' => $isReserved,
16342                            'type' => 1
16343                        ));
16344                    }
16345                }
16346    
16347                // check if busy
16348                if(isset($exceedDailyLimit) && $exceedDailyLimit && !$isReserved && !$liveData->lesson_flg && !$isGuestViewer) {
16349                    if(empty($teacherStatus->status) || (!empty($teacherStatus->status) && $teacherStatus->status == 1)) {
16350                        $isBusy = true;
16351                    }
16352                }
16353    
16354                // NC-5409 : Corporate Limited Plan
16355                if ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.limited') ) {
16356    
16357                    // check if legible
16358                    if (
16359                        (    ($corporateType == Configure::read('corporate_type.limited') && !$isReserved) ||
16360                            (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16361                            $userDuplicateLesson || 
16362                            $unsupportedBrowser ||
16363                            $lessonOnOther
16364                        ) &&
16365                        $studentId
16366                    ) {
16367                        $userNotEligible = 1;
16368                    }
16369    
16370                } elseif ( isset($corporateType) &&  $corporateType == Configure::read('corporate_type.light') ) {
16371    
16372                    $corpLightCondition1 = (
16373                        ($corporateType == Configure::read('corporate_type.light') && !$isReserved) ||
16374                        (!$isReserved && (!$canLessonTextbook || $textbookForReservationOnly)) ||
16375                        $userDuplicateLesson ||
16376                        $unsupportedBrowser ||
16377                        $lessonOnOther
16378                    );
16379                    // check if legible
16380                    if ( $corpLightCondition1 && $studentId) {
16381                        $userNotEligible = 2;
16382                    }
16383                } elseif (
16384                    (
16385                        isset($commonTeacher2['Teacher']['native_speaker_flg']) &&
16386                        $commonTeacher2['Teacher']['native_speaker_flg']
16387                    ) &&
16388                    (
16389                        $user['User']['native_option'] == null ||
16390                        $user['User']['native_option'] == 0
16391                    ) &&
16392                    !$isReserved &&
16393                    !$tmp->live_lesson_flg &&
16394                    !$this->isStudySapuriTosUser
16395                ) {
16396                    $userNotEligible = 3;
16397                    $showNativeSpeakerWarning = true;
16398                } elseif ( // NJ-48797
16399                    (isset($getParentAvatarTeacher['Teacher']['native_speaker_flg']) && $getParentAvatarTeacher['Teacher']['native_speaker_flg']) &&
16400                    ($user['User']['native_option'] == null || $user['User']['native_option'] == 0) && 
16401                    !$isReserved &&
16402                    !$tmp->live_lesson_flg &&
16403                    !$this->isStudySapuriTosUser
16404                ) {
16405                    $showNativeSpeakerWarning = true;
16406                    $userNotEligible = 4;
16407                } else {
16408                    // check if legible
16409                    if ((
16410                        (!$isReserved && (!$canLessonTextbook ||$textbookForReservationOnly)) ||
16411                        $userDuplicateLesson || 
16412                        $unsupportedBrowser || 
16413                        (!$userAdminFlag && ($userFailFlag == 1 || $userDoubleCheckFlag == 2)) ||
16414                        $lessonOnOther
16415                    ) && $studentId) {
16416                        $userNotEligible = 5;
16417                    }
16418                }
16419    
16420                # ~no sudden lesson for sapuri toS user
16421                if ($this->isStudySapuriTosUser && !$isReserved) {
16422                    $userNotEligible = 6;
16423                }
16424    
16425                $_userReservedNowLesson = ($reservedLessonData && $reservedLessonData['Teacher']['id'] == $teacherId) ? true : false;
16426    
16427                if (in_array($user['User']['payment_plan_id'],Configure::read('lite_payment_plans')) && !$_userReservedNowLesson && !$isEmergencyLesson) {
16428                    # disable the lesson button for lite plan if it is not reserved lesson
16429                    $userNotEligible = 7;
16430    
16431                    # add if reserve is still ongoing 
16432                    if($isReserved) {
16433                        $userNotEligible = false;
16434                    }
16435                }
16436    
16437            }            
16438    
16439            switch($stateButton) {
16440                case 2: //proceed_to_the_lesson_immediately
16441                    if (!empty($api['CommonTeacherStatus']['user_id']) &&
16442                        $api['CommonTeacherStatus']['user_id'] != $user['id'] &&
16443                        in_array($api['CommonTeacherStatus']['TeacherStatus']['status'], [1, 3])
16444                    ) {
16445                        $stateButton = 5; //busy
16446                    }
16447                    break;
16448                case 3: // go to reserved lesson
16449                case 32: // dummy lesson
16450                    $teacherStatusColor = 'wait';
16451                    break;
16452                case 15: //other
16453                case 5: //busy
16454                    if(
16455                        ($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') &&
16456                        $membershipTypeReservationOnly
16457                    ) {
16458                        $stateButton = 6;
16459                        $lessonStartBtnText = __d('waiting','予約専用です');
16460                    }
16461                    $teacherStatusColor = 'lesson';
16462    
16463                    break;
16464                default:
16465            }
16466
16467            $studentRemainingSecondsDelay = 0;
16468            $studentRemainingSecondsDelay = !empty($api['studentRemainingSecondsDelay']) ? $api['studentRemainingSecondsDelay'] : $studentRemainingSecondsDelay;
16469    
16470            // show orange button
16471            $lessonOrangeButtonRemaining = $this->triggerOrangeButton($this->Auth->User('id'), $teacherId, $userNotEligible, $unsupportedBrowser, $canLesson['lessonAvailable']);
16472
16473            if (
16474                $canLessonTextbook &&             # - can lesson with the textbook
16475                !$textbookForReservationOnly && # - textbook not for reserve only
16476                !$unsupportedBrowser &&         # - supported browser
16477                $userDuplicateLesson &&         # - has lesson with other teacher
16478                !$this->isStudySapuriTosUser &&    # - not sapuri TOS user
16479                !in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')]) && 
16480                !in_array($user['User']['payment_plan_id'], Configure::read('payment_plan_lightplan'))  # - not lite plan user
16481            ) {
16482                $canMidwayLesson = true;
16483            }
16484        } //end !$isGuestViewer
16485    
16486        $isRedLamp = isset($data['redLamp']) && $data['redLamp'] == "1" ? true : false;
16487        $isRedLamp = (isset($teacherStatus['status']) && $teacherStatus['status'] == 5) ? true : $isRedLamp;
16488        $showLoader = $isGuestViewer ? true : false;    
16489        $suddenLessonFlg = false;
16490        $canDoLive = UserTable::canJoinLiveViewing($user['User']);
16491    
16492        if (
16493            $isReserved && 
16494            (
16495                $this->isStudySapuriUser || 
16496                $this->isStudySapuriTosUser || 
16497                in_array($corporateType, [Configure::read('corporate_type.light'), Configure::read('corporate_type.limited')])
16498            )
16499        ) {
16500            $canDoLive = false;
16501        }
16502    
16503        if(
16504            !$isViewer && 
16505            !$isEmergencyLesson && 
16506            !$isReservedCanSuddenLesson & 
16507            !$canMidwayLesson &&
16508            !$isReserved
16509        ) {
16510            if($teacherStatusColor == 'wait') {
16511                if((!$canLessonTextbook && $this->isStudySapuriUser) || $membershipTypeReservationOnly) {
16512                    $isBusy = true;
16513                }
16514    
16515                if(!( !$canLessonTextbook && $this->isStudySapuriUser ) && !$membershipTypeReservationOnly) {
16516                    $suddenLessonFlg = true;
16517                }
16518            }
16519    
16520            if($teacherStatusColor == 'lesson' || $teacherStatusColor == 'offline') {
16521                if(!($unsupportedBrowser && $teacherStatusColor == 'lesson') || !$membershipTypeReservationOnly) {
16522                    
16523                    if($membershipTypeBlueBtn) {
16524                        $suddenLessonFlg = true;
16525                        $teacherStatusColor = 'wait';
16526                    }
16527                }
16528            }
16529        }
16530    
16531        $canEmergencyLesson = false;
16532        $emergencyBreakTime = ['status' => false];        
16533        $currentMinutes = date("i");
16534        $currentHour = date("H");        
16535
16536        if ($isEmergencyLesson) {
16537            if ($this->isStudySapuriTosUser) {
16538                $nextEmergencySlot = $this->LessonSchedule->getEmergencyTimeSlot();
16539                $nextReserveSlot = $this->LessonSchedule->getNextReservationTimeSlot();
16540                $queryCondition['fields'][] = "(
16541                    ((select smb.id from shift_work_meal_breaks as smb where smb.lesson_time >= '{$nextReserveSlot['start']}' and smb.lesson_time <= '{$nextReserveSlot['end']}' and smb.teacher_id = Teacher.id limit 1) IS NULL) AND 
16542                    ((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextEmergencySlot['start']}' and rs.lesson_time <= '{$nextEmergencySlot['end']}' and rs.status = 1 and rs.teacher_id = Teacher.id limit 1) IS NULL)
16543                    ) as can_emergency_lesson";
16544                $queryCondition['fields'][] = "((Select rs.id from lesson_schedules as rs where rs.lesson_time >= '{$nextReserveSlot['start']}' and rs.lesson_time <= '{$nextReserveSlot['end']}' and rs.status = 1 and rs.user_id = {$studentId} limit 1) IS NULL) 
16545                    as student_no_next_reservation";
16546            }
16547
16548            $commonTeacherStatusParams = array(
16549                'page_display' => 'listTeacher',
16550                'query_conditions' => $queryCondition
16551            );
16552            $emergencyLessonOnair = $this->CommonTeacherStatus->getAllStatus($commonTeacherStatusParams);
16553            
16554            if (
16555                $this->isStudySapuriTosUser &&
16556                !$isReserved &&
16557                isset($emergencyLessonOnair[0]['can_emergency_lesson']) && 
16558                isset($emergencyLessonOnair[0]['student_no_next_reservation']) && 
16559                $emergencyLessonOnair[0]['can_emergency_lesson'] && # -can emergency
16560                $emergencyLessonOnair[0]['student_no_next_reservation']    # - no next reservation
16561            ) {
16562                $canEmergencyLesson = true;
16563            }
16564
16565            # ~if emergency lesson break time
16566            if ( !$isReserved && (($currentMinutes >= 26 && $currentMinutes <= 29) || ($currentMinutes >= 56 && $currentMinutes <= 59))) {
16567                $canEmergencyLesson = false;
16568                $emergencyBreakTime['status'] = true;
16569                $emergencyBreakTime['time_span'] = '['.$currentHour.'時26分 ~ '.$currentHour.'時30分]['.$currentHour.'時56分 ~ '.$currentHour.'時00分]';
16570                $emergencyBreakTime['time_return'] = '['.$currentHour.'時30分]['.$currentHour.'時00分]';
16571            }
16572        }
16573    
16574        $isAvatar = $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 || $api['CommonTeacherStatus']['Teacher']['avatar_parent_flg'] == 1 ? true : false;
16575    
16576        // lesson alert
16577        $lessonAlertMsg = [];
16578        $lessonAlertStatus = '';
16579    
16580        // if emergency lesson break time
16581        if ($isEmergencyLesson && $emergencyBreakTime['status']) {
16582            $lessonAlertMsg = [
16583                ['text' => __d('waiting','しばらくお待ちください。')],
16584                ['text' => sprintf(__d('waiting','%sの間は緊急時予約レッスンにご入室いただけません。'), $emergencyBreakTime['time_span'])],
16585                ['text' => sprintf(__d('waiting','%sまでお待ちください。'), $emergencyBreakTime['time_return'])]
16586            ];
16587            $lessonAlertStatus = 'emergency_lesson_break_time';
16588        }
16589    
16590        if (
16591            (isset($exceedDailyLimit) && $exceedDailyLimit) &&
16592            !$isReserved &&
16593            !$isAvatar
16594        ) {
16595            $lessonAlertMsg = [
16596                ['text' => __d('waiting','同一講師との連続した今すぐレッスンはレッスン完了から60分空けて再度受講が可能となります (講師の独占を緩和するため) 。')],
16597                ['text' => __d('waiting','※異なる講師を選択した場合は何度でも連続で今すぐレッスンの受講が可能です (今すぐレッスン回数無制限) 。')],
16598                ['text' => __d('waiting','※回線不具合等で短時間レッスンとなった場合は、レッスン合計時間が25分に達するまでの間は同一講師と連続で今すぐレッスンの受講が可能です。')]
16599            ];
16600            $lessonAlertStatus = 'exceed_daily_limit';
16601        }
16602    
16603        // set localize url
16604        if (
16605            isset($get['la']) && in_array($get['la'], array_flip(Configure::read('pc_allowed_currencies'))) &&
16606            $get['la'] != Configure::read('default.user_language')
16607        ) {
16608            $localizeUrl = myTools::getUrl() . '/' . $get['la'];
16609        } else {
16610            $localizeUrl = myTools::getUrl();
16611        }
16612    
16613        $displayFamilyAlert = false;
16614        if (
16615            isset($this->sharedUserData['User']['parent_id']) &&
16616            !is_null($this->sharedUserData['User']['parent_id'])
16617        ) {
16618            $parent = $this->User->find('first', array(
16619                'fields' => array(
16620                    'User.id',
16621                    'User.hash16',
16622                    'User.charge_flg'
16623                ),
16624                'conditions' => array(
16625                    'User.id' => $this->sharedUserData['User']['parent_id']
16626                ),
16627                'recursive' => -1
16628            ));
16629    
16630            if ($parent && $parent['User']['charge_flg'] != 1) {
16631                $displayFamilyAlert = true;
16632            }
16633        }
16634    
16635        $device = false;
16636        if (strpos($ua, 'Silk') !== false) {
16637            $device = 'kindle';
16638        } else if (strpos($ua, 'Android') !== false) {
16639            $device = 'andriod';
16640        } else if (strpos($ua, 'iPhone') !== false) {
16641            $device = 'ios';
16642        } else if (strpos($ua, 'iPad') !== false) {
16643            $device = 'ios';
16644        } else if (strpos($ua, 'iPod') !== false) {
16645            $device = 'ios';
16646        } else {
16647            $device = 'pc';
16648        }
16649    
16650        $corporateIndividualUser = false;
16651        $corporateTypes = Configure::read('corporate_type_arr');
16652        $corporateTypeUserTable = myTools::getCoporateTypeUsingPaymentPlanId($user['User']['payment_plan_id']);
16653        if (isset($user['User']['corporate_id'])) {
16654            $corporateAdminPaymentMethod = $this->Corporate->getPaymentMethod($user['User']['corporate_id']);
16655            $corporateIndividualUser = $corporateAdminPaymentMethod == 1 ? true : false;
16656        }
16657    
16658        if (
16659            !$this->isStudySapuriUser &&
16660            $lessonType == Configure::read('lesson.type.reservation') &&
16661            ($uOnair && $uOnair['leave_lesson']) # - already left the reserved lesson
16662        ) {
16663            $isReservedCanLessonViewing = true;
16664        }
16665    
16666        $showTakeBusinessTestModal = false;
16667        if (isset($user['User']['corporate_id'])) {
16668            $showTakeBusinessTestModal = false;
16669            $isTakenBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_flg'])) ? $user['User']['monthly_speaking_business_attended_flg'] : 0;
16670            $isMustTakeBusinessTestFlg = (isset($user['User']['monthly_speaking_business_attended_must_flg'])) ? $user['User']['monthly_speaking_business_attended_must_flg'] : 0;
16671            $corporateUserDate = time();
16672            $twentyPlusDayOfTheMonth = strtotime(date('Y-m-20'));
16673    
16674            if (
16675                ($isTakenBusinessTestFlg == 0 && $isMustTakeBusinessTestFlg == 1) &&
16676                !$isReserved &&
16677                (
16678                    $corporateUserDate >= $twentyPlusDayOfTheMonth ||
16679                    (
16680                        $userAdminFlag == 1 ||
16681                        (
16682                            isset($user["User"]["nickname"]) &&
16683                            strpos(strtoupper($user["User"]["nickname"]), '%%%TEST%%%') !== false
16684                        )
16685                    )
16686                )
16687            ) {
16688                $showTakeBusinessTestModal = true;
16689            }
16690        }        
16691    
16692        $liveLessonText = $liveData->lesson_flg ? __d('waiting','予約レッスン(LIVE)へ進む') : __d('waiting','予約レッスンへ進む');
16693        $button = $buttonStates[$stateButton];
16694    
16695        if(!$isGuestViewer) {
16696            $json = array_merge($json, [
16697                'button' => $button,
16698                'canDoLive' => $canDoLive,
16699                'canEmergencyLesson' => $canEmergencyLesson,
16700                'canLesson' => $canLesson,
16701                'canLessonTextbook' => $canLessonTextbook,
16702                'canMidwayLesson' => $canMidwayLesson,
16703                'checkBadge' => $checkBadge,
16704                'commonTeacher2' => $commonTeacher2,
16705                'corporateIndividualUser' => $corporateIndividualUser,
16706                'corporatePlanName' => isset($corporateTypeUserTable) ? (isset($corporateTypes[$corporateTypeUserTable]) ? $corporateTypes[$corporateTypeUserTable] : '') : '',
16707                'corporateType' => $corporateType,
16708                'corporateUserFlg' => $corporateUserFlg,
16709                'corpLightCondition' => $corpLightCondition1,
16710                'device' => $device,
16711                'displayFamilyAlert' => $displayFamilyAlert,
16712                'dummyLessonRoom' => $hasLessonBeforeActualTime,
16713                'emergencyBreakTime' => $emergencyBreakTime,
16714                'exceedDailyLimit' => isset($exceedDailyLimit) ? $exceedDailyLimit : false,
16715                'hasLessonBeforeActualTime' => $hasLessonBeforeActualTime,
16716                'homeFlg' => $api['CommonTeacherStatus']['Teacher']['home_flg'],
16717                'isAvatar' => $isAvatar,
16718                'isBusy' => $isBusy,
16719                'isEmergencyLesson' => $isEmergencyLesson,
16720                'isNormalLitePlanUser' => $isNormalLitePlanUser,
16721                'isRedLamp' => $isRedLamp,
16722                'isReserved' => $isReserved,
16723                'isReservedCanLessonViewing' => $isReservedCanLessonViewing,
16724                'isReservedCanSuddenLesson' => $isReservedCanSuddenLesson,
16725                'isStudySapuriTosUser' => $this->isStudySapuriUser,
16726                'isViewer' => $isViewer,
16727                'lessonAlertMsg' => $lessonAlertMsg,
16728                'lessonAlertStatus' => $lessonAlertStatus,
16729                'lessonOnOther' => $lessonOnOther,
16730                'lessonOrangeButtonRemaining' => $lessonOrangeButtonRemaining,
16731                'lessonType' => $lessonType,
16732                'liveData' => $liveData,
16733                'liveLessonFlg' => $liveLessonFlg ?? null,
16734                'liveLessonText' => $liveLessonText,
16735                'liveStatus' => $liveStatus,
16736                'localizeUrl' => $localizeUrl,
16737                'membershipTypeBlueBtn' => $membershipTypeBlueBtn,
16738                'membershipTypeReservationOnly' => $membershipTypeReservationOnly,
16739                'oOnair' => $oOnair,
16740                'uOnair' => $uOnair,
16741                'onGoingLesson' => $onGoingLesson,
16742                'paymentPlanId' => $user['User']['payment_plan_id'],
16743                'points' => $this->UsersPoint->getCurrentUserPoint($studentId),
16744                'redirectPlanUrl' => $redirectPlanUrl,
16745                'reservedLessonData' => $reservedLessonData,
16746                'sapuriCoin' => $sapuriCoin,
16747                'scheduleReservationData' => $scheduleReservationData,
16748                'showLoader' => $showLoader,
16749                'showNativeSpeakerWarning' => $showNativeSpeakerWarning,
16750                'showTakeBusinessTestModal' => $showTakeBusinessTestModal,
16751                'stateButton' => $stateButton,
16752                'stateButtonApi' => $api['teacher']['state_button'],
16753                'studentId' => $studentId,
16754                'suddenLessonFlg' => $suddenLessonFlg,
16755                'teacherAvatarFlg' => $api['CommonTeacherStatus']['Teacher']['avatar_flg'] == 1 ? true : false,
16756                'teacherLeaveNotice' => $teacherLeaveNotice,
16757                'teacherStatus' => $teacherStatus,
16758                'teacherStatusApi' => $_teacherStatus,
16759                'teacherStatusColor' => $teacherStatusColor,
16760                'textbookForReservationOnly' => $textbookForReservationOnly,
16761                'unverifiedSMS' => $stateButton == 7 ? true : false,
16762                'unsupportedBrowser' => $unsupportedBrowser,
16763                'use7DaysTrialModal' => $use7DaysTrialModal,
16764                'userAdminFlag' => $userAdminFlag,
16765                'userDoubleCheckFlag' => $userDoubleCheckFlag,
16766                'userDuplicateLesson' => $userDuplicateLesson,
16767                'userFailFlag' => $userFailFlag,
16768                'userMembershipType' => $this->userMembershipType,
16769                'userNativeOption' => $user['User']['native_option'],
16770                'userNotEligible' => $userNotEligible
16771            ]);
16772
16773            if($membershipTypeReservationOnly) {
16774                $json['lessonStartBtnText'] = __d('waiting','予約専用です');
16775            }
16776
16777            if($suddenLessonFlg) {
16778                if($use7DaysTrialModal) {
16779                    $json['suddenLessonStatus'] = 'use7DaysTrialModal';
16780                } else if (!empty(trim($redirectPlanUrl))) {
16781                    $json['suddenLessonStatus'] = 'redirectPlanUrl';
16782                } else if ($showNativeSpeakerWarning) {
16783                    $json['suddenLessonStatus'] = 'showNativeSpeakerWarning';
16784                } else if ($unsupportedBrowser) {
16785                    $json['suddenLessonStatus'] = 'unsupportedBrowser';
16786                } else if (!$canLessonTextbook) {
16787                    $json['suddenLessonStatus'] = 'cannotLessonTextbook';
16788                } else if (!empty($teacherLeaveNotice)) {
16789                    $json['suddenLessonStatus'] = 'teacherLeaveNotice';    
16790                }
16791
16792                if(!empty($json['suddenLessonStatus'])) {
16793                    $json['validateSuddenLessonFlg'] = false;
16794                } else {
16795                    $json['validateSuddenLessonFlg'] = true;
16796                }
16797            }
16798            
16799        } else if ($isViewer || $isGuestViewer) {
16800            $json = array_merge($json, [
16801                'canLesson' => $canLesson
16802            ]);
16803        }
16804
16805        if($env != 'PRODUCTION') {
16806            $json['api'] = $api;
16807            $json['commonTeacher2'] = $commonTeacher2;
16808            $json['emergencyLessonOnair'] = $emergencyLessonOnair;
16809            $json['tmpLessonOnAir'] = $tmp;
16810        }
16811    
16812        return json_encode($json);
16813    }
16814
16815    public function checkLessonStartButtonCounselor() {
16816        $this->autoRender = false;
16817        $this->layout = false;
16818        $userId = $this->Auth->user('id');
16819
16820        // if api token is not set
16821        if (empty($this->sharedUserData['User']['api_token'])) {
16822            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16823            $this->Session->write('Auth.User.api_token', $userApiToken);
16824        }
16825
16826        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16827        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16828        $TeachersCounselorDetailController->params = [
16829            'nc_terminal_type' => 1, // pc
16830            'users_api_token' => $this->Auth->user('api_token'),
16831            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16832            'device_type' => 2
16833        ];
16834        
16835        $data = json_decode($TeachersCounselorDetailController->counselorDetail(), true);
16836        $teacherId = $data['available_teacher'] ?? '';
16837        $status = $data['teacher']['status'] ?? '';
16838        $exceedDailyLimit = $data['exceed_daily_limit'] ? 1 : 0;
16839
16840        if ($status == 3) {
16841            $status = 2;
16842        } elseif ($status == 4) {
16843            $status = 3;
16844        }
16845
16846        return json_encode(
16847            array(
16848                'user_id' => $userId,
16849                'teacher_id' => $teacherId,
16850                'status' => $status,
16851                'exceed_daily_limit' => $exceedDailyLimit        
16852            )
16853        );
16854        
16855    }
16856
16857    public function checkLessonStartButtonCS() {
16858        $this->autoRender = false;
16859        $this->layout = false;
16860        $userId = $this->Auth->user('id');
16861        
16862        // if api token is not set
16863        if (empty($this->sharedUserData['User']['api_token'])) {
16864            $userApiToken = $this->User->generateAndSaveApiToken($userId);
16865            $this->Session->write('Auth.User.api_token', $userApiToken);
16866        }
16867
16868        myTools::initializeApiTunnel(array('TeachersCounselorDetailController'));
16869        $TeachersCounselorDetailController = new TeachersCounselorDetailController();
16870        $TeachersCounselorDetailController->params = [
16871            'nc_terminal_type' => 1, // pc
16872            'users_api_token' => $this->Auth->user('api_token'),
16873            'app_version' => Configure::read('max_sudden_lesson_counselor.app_version.2'),
16874            'device_type' => 2
16875        ];
16876
16877        if($this->userMembershipType === 12) {
16878            $csParams = array(
16879                'user_id' => $userId,
16880                'user_data' => $this->sharedUserData['User'],
16881                'customer_support_flg' => 1
16882            );
16883
16884            $data = json_decode( $this->LessonOnair->checkCounselorTeacherButtonStatus($csParams), true);
16885            $status = $data['res'] ?? '';
16886        } else {
16887            $data = json_decode($TeachersCounselorDetailController->customerSupportDetail(), true);
16888            $status = $data['teacher']['status'] ?? '';
16889        }
16890
16891        $teacherId = $data['available_teacher'] ?? '';
16892        $exceedDailyLimit = !empty($data['exceed_daily_limit']) ? 1 : 0;
16893
16894        if ($status == 3) {
16895            $status = 2;
16896        } elseif ($status == 4) {
16897            $status = 3;
16898        }
16899
16900        // Check if user exceeds daily limit for customer support lessons
16901        if ($userId) {
16902            $csList = $this->Teacher->getCustomerSupportTeachers();
16903            $csExceedLimitCheck = $this->LessonOnairsLog->checkExceedCSLimit($userId, $csList['customerSupportId']);
16904            if ($csExceedLimitCheck) {
16905                $exceedDailyLimit = 1;
16906                $status = 0;
16907            }
16908        }
16909
16910        return json_encode([
16911            'user_id' => $userId,
16912            'teacher_id' => $teacherId,
16913            'status' => $status,
16914            'exceed_daily_limit' => $exceedDailyLimit,
16915            'membership_type' => $this->userMembershipType
16916        ]);
16917    }
16918    public function updateLessonSystemTrouble() {
16919        $this->autoRender = false;
16920        $this->layout = false;
16921        $troubleResponse = false;
16922
16923        if ($this->request->is('ajax')) {
16924            $chatHash = $this->request->data['chat_hash'] ?? '';
16925            $status = $this->request->data['status'] ?? 0;
16926            $teacherID = $this->request->data['teacher_id'] ?? null;
16927            $storeMemcache = $this->request->data['store_memcache'] ?? 0;
16928
16929            if ($storeMemcache && $chatHash) {
16930                $memcached = new myMemcached();
16931                // $memcached->set(array(
16932                //     'key' => 'hide_connection_modal_flg_'.$teacherID.'-'.$chatHash,
16933                //     'value' => 1,
16934                //     'expire' => 86400 //-- 24hrs
16935                // ));
16936                $troubleResponse = true;
16937                $this->log("successfully added memcache");
16938            }
16939        }
16940
16941        return json_encode(array('result' => $troubleResponse));
16942    }
16943    
16944    public function setAppreciationModalFinish(){
16945        $this->autoRender = false;
16946        $this->layout = false;
16947
16948        if(empty($this->request->data['chat_hash'])){
16949            return false;
16950        }
16951
16952        $chat_hash = $this->request->data['chat_hash'];
16953
16954        if (!class_exists('myMemcached')) {
16955            App::uses('myMemcached', 'Lib');
16956        }
16957        $memcached = new myMemcached();
16958        $memcached->set(array(
16959            'key' => "appreciation_done_".$chat_hash,
16960            'value' => 1,
16961            'expire' => 86400 // 1 day
16962        ));
16963
16964        return true;
16965    }
16966}